2015-03-23 1 views
0

j'ai un ensemble de données avec les numéros suivants:Python, trouver une ligne spécifique basée sur plusieurs coniditions dans une ligne

1 30.0 13.4545 
2 30.0 10.5578 
3 30.0 12.5578 
4 5.0 5.224 

Je le code suivant qui imprime la ligne avec le flotteur le plus petit sur la base deuxième flotteur.

with open(fn) as f: 
    print min(f, key=lambda line: float(line.split()[1])) 

J'essaie de comprendre comment imprimer la ligne avec le plus grand premier flotteur, mais si les flotteurs sont les mêmes, puis imprimer la ligne avec le plus petit 3 flottant au sein du groupe de lignes avec le 1er flotteurs

il devrait imprimer:

2 30.0 10.5578 

Je pensais que quelque chose comme ceci:

with open(fn) as f: 
     cpu = max(f, key=lambda line: float(line.split()[1])) 
     for line in f: 
      if cpu in line > 1: 
       print min(f, cpu, key=lambda line: float(line.split()[1]))  

mais pas de chance, je continue d'imprimer soit le nombre max ou min sans regarder les deux conditions.

+2

Étant donné que votre condition dépend des valeurs de plusieurs lignes que vous êtes soit allez avoir à lire le fichier en mémoire pour le lire plusieurs fois.Le code que vous avez ne fonctionne pas parce que l'appel 'max()' lit le fichier entier, il n'y a plus rien à consommer dans la boucle 'for' suivante. – martineau

Répondre

3

Alors qu'il est possible de faire ce que vous demandez avec un lambda, le lambda résultant sera une abomination impie qui tue aussi les chatons. En toute rigueur, ce n'est pas un bon endroit pour un lambda car, à moins d'un code incroyablement affreux, l'assignation de variables n'est pas possible dans un lambda, et l'assignation de variables rendrait ce problème beaucoup plus facile.

Maintenant, sur le problème lui-même. Votre question est, essentiellement, comment trier les éléments dans l'ordre décroissant par leur deuxième valeur, puis l'ordre croissant par leur troisième valeur.

L'élément avec le plus grand deuxième élément et le plus petit troisième élément peut également être décrit comme l'élément ayant le plus grand deuxième élément et le plus petit élément négatif.

Pour cela en Python, nous pouvons créer une fonction à utiliser comme clé. Cette fonction prend chaque ligne, coupe le premier élément de la ligne (parce que ce n'est pas pertinent), et rend la troisième valeur négative.

Vous pouvez le faire avec la liste compréhensions:

def myKey(line): 
    key = [float(i) for i in line.split()[1:]] 
    key[1] *= -1 
    return key 

print max(x, key=myKey) 

Ou avec map()

def myKey(line): 
    key = map(float, line.split()[1:]) 
    key[1] *= -1 
    return key 

print max(x, key=myKey) 

Et, bien sûr, la sortie est:

2 30.0 10.5578 
+0

merci, j'ai fait en écrivant à deux fichiers séparés, et trouver le maximum dans un, puis écrire dans un autre fichier et trouver le maximum de cet ensemble, mais cela ne semble pas trop efficace – octain

+0

J'aime inverser le genre dans un colonne en le multipliant par -1. Bon travail! –

+0

J'ai essayé ceci et je reçois l'index de la liste IndexError hors de portée pointant sur la clé [1] * = -1' – octain

1

Ce n'est pas réellement aussi mauvais que c'est fait, si votre seul but est de lire le fichier une fois et obtenir cette ligne.

max_col2 = -float('inf') 
min_col3 = float('inf') 
targetline = None 
for line in f: 
    idx, col2, col3 = line.split() 
    if col2 > max_col2: 
     targetline = line.strip() 
     max_col2 = col2 
    if col2 == max_col2 and col3 < min_col3: 
     targetline = line.strip() 
     min_col3 = col3 

targetline sera votre ligne demandée.

2
def key(line): 
    x,y = line.split()[1:] 
    return (float(x),-float(y)) 

with open(fn) as f:  
    max((l for l in f if l.strip()),key=key) 

Ou avec lambda,

with open(fn) as f:  
    max((l for l in f if l.strip()),key=lambda x: (float(x.split()[1]),-float(x.split()[2])))