Feedback su implementazione della funzione che confronta i segni interi in Python

StackOverflow https://stackoverflow.com/questions/4558326

  •  14-10-2019
  •  | 
  •  

Domanda

Ho fatto una piccola funzione che, data una tupla, paragona se tutti gli elementi in questo tupla è dello stesso segno.

per es., Tuple = [-1, -4, -6, -8] è buono, mentre [-1, -4, 12, -8] è male. Io non sono sicuro di aver fatto la più intelligente implementazione, quindi so che questo è il posto giusto per chiedere.

def check_consistent_categories(queryset):
    try:
        first_item = queryset[0].amount

        if first_item < 0:
            for item in queryset:
                if item > 0:
                    return False
            return True
        else:
            for item in queryset:
                if item < 0:
                    return False
            return True
    except:
        return False
È stato utile?

Soluzione

Questo aiuto potrebbe voi:

def all_same_sign(ints):
    return all(x < 0 for x in ints) or all(x > 0 for x in ints)

Si può decidere di cambiare per <= e> = a seconda di come si vuole trattare 0.

Altri suggerimenti

Dopo @ soluzione di EOL, ma opere senza lista indicizzazione o l'iterazione più volte.

def all_same_sign(sequence):
    items = iter(sequence)
    try:
        first = items.next() > 0
    except StopIteration:
        return True
    return all((item > 0) == first for item in items)

Questa è verificato anche a me, ma non approfitta di tutte / qualsiasi cortocircuito:

def all_same_sign(sequence):
    return len(set(item > 0 for item in sequence)) <= 1

Un solo nit indipendenti, dal momento che si sta facendo questo:

try:
    [...]
except:
    [...]

Stai ignorando all delle eccezioni, essere molto attenti mio amico, questo sarà nascosto un sacco di bug, invece sempre essere precisi, mentre facendo la gestione delle eccezioni per esempio:

try:
    [...]
except IndexError:
    # Handle out of index
except IOError:
    # Handle I/O error

ecc. Tenetelo a mente, mentre la codifica di un grande applicazione Python.

Ecco un bel modo divinatorio di fare questo (utilizzando all()):

from math import copysign

sign = lambda x: copysign(1, x)  # Sign function

def check_consistent_categories(sequence):
    main_sign = sign(sequence[0])
    return all(sign(y) == main_sign for y in sequence)

(per Python 2.6+, che ha introdotto la funzione math.copysign()). Questa soluzione ritiene che 0 è positivo.

soluzione Mark Byers' è più flessibile, però, ed è anche probabilmente più leggibile.

Perché non approfittare del fatto che, se tutti i numeri sono lo stesso segno, allora la somma del valore assoluto di ogni singolo numero sarà pari al valore assoluto della somma di ogni numero?

def check_sign(queryset):
    return abs(sum(queryset)) == sum(map(abs, queryset))

Esempio che mostra i dettagli del Math

Caso 1: Tutti i numeri hanno lo stesso segno

a = (-1, -4, -8)
sum(a) = -13
abs(sum(a)) = 13        # the absolute value of the tuple's sum
map(abs, a) = [1, 4, 8]
sum(map(abs, a)) = 13   # the tuple's sum of each element's absolute value

Entrambi i metodi producono 13, in modo che i segni sono gli stessi.

Caso 2: Non tutti i numeri hanno lo stesso segno

b = (-1, 4, 8)
sum(b) = 11
abs(sum(b)) = 11        # the absolute value of the tuple's sum 
map(abs, b) = [1, 4, 8]
sum(map(abs, b)) = 13   # the tuple's sum of each element's absolute value

I metodi producono numeri differenti (11 e 13), in modo che i segni non sono tutti uguali.

Ecco uno che funziona bene con i generatori ecc troppo

def all_same_sign(ints):
    ints = iter(ints)
    first_is_positive = next(ints) > 0
    return all( (x>0) == first_is_positive for x in ints)

Se ints è vuoto, si ottiene un'eccezione StopIteration.

Questa versione gorups 0 con i numeri negativi. Utilizzare >= se desiderate gruppo con i numeri positivi anziché

def all_same_sign(iterable):
    # Works with any iterable producing any items that can be compared to zero.
    # Iterates through the input no more than once, and this fact is immediately
    # obvious from the code.
    # Exits as soon as a bad combination has been detected.
    pos = neg = zero = False
    for item in iterable:
        if item > 0:
            pos = True
        elif item < 0:
            neg = True
        else:
            zero = True
        # Adjust the following statement if a different
        # treatment of zero is required.
        # Redundant parentheses added for clarity.
        if (pos and neg) or zero:
            return False
    return True

Se i numeri sono ordinati avete solo bisogno di confrontare le estremità. Se non li si poteva ordinare:

def same_sign(numbers):
    numbers = sorted(numbers)
    #if numbers[0]==0: return True                Uncomment if you consider 0 positive
    if numbers[0]*numbers[-1]>0: return True
    return False

Se si è modificato questo per >=0 a zero sarebbe considerato segno neutro. Non sono sicuro se questa è un'implementazione migliore rispetto alle risposte attuali, ma potrebbe essere più veloce per grandi insiemi di dati.

Utilizzando il principio che moltiplicando i numeri dà un risultato positivo se tutti lo stesso, altrimenti negativo,

import operator

def all_same_sign(intlist):
    return reduce(operator.mul, intlist) > 0

>>> all_same_sign([-1, -4, -6, -8])
True
>>> all_same_sign([-1, -4, 12, -8])
False

Questa non gestisce zeri anche se ...

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top