Tengo una lista de diccionarios que quiero filtrar.

[{"Slope": -0.562, "Count": 3},
 {"Slope": -0.362, "Count": 6},
 {"Slope": -0.762, "Count": 8},
 {"Slope": -0.562, "Count": 12},
 {"Slope": 2.5, "Count": 34},
 {"Slope": 1.52, "Count": 2},
 {"Slope": .56, "Count": 6}]

Mi objetivo es obtener una lista de dos diccionarios. Uno con el "conteo más alto y una pendiente POSITVE" y el otro con el "conteo más alto y la pendiente NEGATIVA".

Mi plan era filtrar todos los positivos y negativos, luego ordenar cada lista y luego crear una nueva lista con el primer registro de cada una.

Ordenar la lista no es un problema para mí, ¡tengo esto!

lines_lst.sort(key=lambda i: i['lines_count'])

Pero el filtrado no parece funcionar cuando intento esto, ya que devuelve un diccionario.

positive_lines = next(item for item in lines_lst if item["Slope"] > 0)

¿Alguien tiene una solución que termine con lo siguiente?

[{"Slope": -0.562, "Count": 12},{"Slope": 2.5, "Count": 34}]
4
Lewis Morris 11 oct. 2019 a las 20:38

6 respuestas

La mejor respuesta

Desea max y min ... úselos y aplique una función de tecla adecuada; de hecho, con las tuplas solo necesita max:

data = [{"Slope": -0.562, "Count": 3},
        {"Slope": -0.362, "Count": 6},
        {"Slope": -0.762, "Count": 8},
        {"Slope": -0.562, "Count": 12},
        {"Slope": 2.5, "Count": 34},
        {"Slope": 1.52, "Count": 2},
        {"Slope": .56, "Count": 6}]

m1 = max(data, key= lambda x: (x["Slope"]>0, x["Count"]))
m2 = max(data, key= lambda x: (x["Slope"]<0, x["Count"]))

result = [m1,m2]

print(result)

Salida:

[{'Slope': 2.5, 'Count': 34}, {'Slope': -0.562, 'Count': 12}]

Las tuplas se ordenan por el primer valor, luego por el segundo valor: puede construir tuplas y usarlas como función de tecla máxima.

6
Patrick Artner 11 oct. 2019 a las 18:10

Para abordar su información adicional en la respuesta de Patrick, puede hacer esto para ordenar primero las listas negativas / positivas:

positives = sorted((v for v in data if v['Slope'] >= 0), key=lambda x: x['Count'])
negatives = sorted((v for v in data if v['Slope'] < 0), key=lambda x: x['Count'])

# positives:
# [{'Slope': 1.52, 'Count': 2}, {'Slope': 0.56, 'Count': 6}, {'Slope': 2.5, 'Count': 34}]

# negatives:
# [{'Slope': -0.562, 'Count': 3}, {'Slope': -0.362, 'Count': 6}, {'Slope': -0.762, 'Count': 8}, {'Slope': -0.562, 'Count': 12}]

Obtener el máximo en este punto es simple. Solo recupera el último elemento:

max_pox = positives[-1]     # {'Slope': 2.5, 'Count': 34}
max_neg = negatives[-1]     # {'Slope': -0.562, 'Count': 12}

O si lo prefiere en forma de lista:

[x[-1] for x in (negatives, positives)]

# [{'Slope': -0.562, 'Count': 12}, {'Slope': 2.5, 'Count': 34}]
1
r.ook 11 oct. 2019 a las 19:12

Puede pasar una expresión del generador a max():

>>> max((d for d in lines_lst if d["Slope"] > 0), key=lambda d: d["Count"])
{'Slope': 2.5, 'Count': 34}
>>> max((d for d in lines_lst if d["Slope"] < 0), key=lambda d: d["Count"])
{'Slope': -0.562, 'Count': 12}

Por supuesto, esta solución itera a través de lines_lst dos veces. Si tiene una entrada realmente grande, puede recorrerla una vez, con avidez, haciendo un seguimiento del máximo / mínimo en ejecución:

import sys

max_pos, max_neg = {"Count": -sys.maxsize}, {"Count": -sys.maxsize}
for d in lines_lst:
    ct = d["Count"]
    if d["Slope"] > 0 and ct > max_pos["Count"]:
        max_pos = d
    elif d["Slope"] < 0 and ct > max_neg["Count"]:
        max_neg = d

Pero en Python-land, esto probablemente solo sea valioso si su entrada es realmente grande y difícil de manejar.

Tenga en cuenta que en ambos casos, _más modificaciones a max_pos / max_neg constituyen modificaciones a los miembros de lines_lst, porque esos miembros son diccionarios mutables.

2
Brad Solomon 11 oct. 2019 a las 17:54

¿Esto funciona?

data = [{"Slope": -0.562, "Count": 3},
{"Slope": -0.362, "Count": 6},
{"Slope": -0.762, "Count": 8},
{"Slope": -0.562, "Count": 12},
{"Slope": 2.5, "Count": 34},
{"Slope": 1.52, "Count": 2},
{"Slope": .56, "Count": 6}]
positive_lines = []
negative_lines = []
for i in range(len(data)):
    if data[i]["Slope"] < 0:
        negative_lines.append(data[i])
    else:
        positive_lines.append(data[i])
max_counts = []
max_counts.append(max(positive_lines, key=lambda x:x['Count']))
max_counts.append(max(negative_lines, key=lambda x:x['Count']))
print(max_counts)

Salida:

[{'Slope': 2.5, 'Count': 34}, {'Slope': -0.562, 'Count': 12}]
0
Celius Stingher 11 oct. 2019 a las 17:48

Puede hacerlo de la siguiente manera:

inList = [{"Slope": -0.562, "Count": 3},
{"Slope": -0.362, "Count": 6},
{"Slope": -0.762, "Count": 8},
{"Slope": -0.562, "Count": 12},
{"Slope": 2.5, "Count": 34},
{"Slope": 1.52, "Count": 2},
{"Slope": .56, "Count": 6}]

maximum = max(filter(lambda elem: elem['Slope'] > 0, inList), key=lambda e: e['Count'])
minimum = max(filter(lambda elem: elem['Slope'] < 0, inList), key=lambda e: e['Count'])

Esto devolverá:

{'Slope': 2.5, 'Count': 34}
{'Slope': -0.562, 'Count': 12}
1
Vasilis G. 11 oct. 2019 a las 17:44

Cree una clave Count2 que sea negativa para pendientes negativas. Luego ordena por Count2 y toma el primer y último elemento.

lines_lst = [{"Slope": -0.562, "Count": 3},
 {"Slope": -0.362, "Count": 6},
 {"Slope": -0.762, "Count": 8},
 {"Slope": -0.562, "Count": 12},
 {"Slope": 2.5, "Count": 34},
 {"Slope": 1.52, "Count": 2},
 {"Slope": .56, "Count": 6}]


for i in range(len(lines_lst)):
    lines_lst[i]['Count2'] = lines_lst[i]['Count']*lines_list[i]['Slope']/abs(lines_list[i]['Slope'])

lines_lst.sort(key=lambda i: i['Count2'])

[lines_lst[0], lines_lst[-1]]

1
ymzkala 11 oct. 2019 a las 17:56
58346105