I have the following snippet:
list = [{"num":1,"test":"A"},{"num":6,"test":"B"},{"num":5,"test":"c"},{"num":1,"test":"D"}]
min = None
for x in list:
if x["num"]<min or min==None:
min=x["num"]
print(min)
print([index for index, element in enumerate(list)
if min == element["num"]])
Which doesn't really output anything useful, my objective was to output, as said in the title, the dictionaries with "1" in num.
A noob question I know, but this is my first contact with the language.
Thanks!
min() takes a key argument that lets you specific how to calculate the min. This will let you find an object with the min num value. You can then use that to find all of them with a list comprehension (or similar method).
l = [{"num":1,"test":"A"},{"num":6,"test":"B"},{"num":5,"test":"c"},{"num":1,"test":"D"}]
m = min(l, key=lambda d: d['num'])
# {'num': 1, 'test': 'A'}
[item for item in l if item['num'] == m['num']]
# [{'num': 1, 'test': 'A'}, {'num': 1, 'test': 'D'}]
You need to set min to an arbitrarily large number at the beginning of the program. I set it to 500. You then have to make you're checking if the "num" value is less than or equal to min, otherwise it will not grab both 1 values.
list = [{"num":1,"test":"A"},{"num":6,"test":"B"},{"num":5,"test":"c"},{"num":1,"test":"D"}]
min = 500
for x in list:
if x["num"]<=min or min==None:
min=x["num"]
print(x)
print(min)
You can try with this:
list_=[{"num":1,"test":"A"},{"num":6,"test":"B"},{"num":5,"test":"c"},{"num":1,"test":"D"}]
min_=min(list_,key=lambda x: x["num"])
min_ = min_["num"]
l=list(filter(lambda x: x["num"]==min_,list_))
print(l)
Related
I was making a program where first parameter is a list and second parameter is a list of dictionaries. I want to return a list of lists like this:
As an example, if this were a function call:
make_lists(['Example'],
[{'Example': 'Made-up', 'Extra Keys' : 'Possible'}]
)
the expected return value would be:
[ ['Made-up'] ]
As an second example, if this were a function call:
make_lists(['Hint', 'Num'],
[{'Hint': 'Length 2 Not Required', 'Num' : 8675309},
{'Num': 1, 'Hint' : 'Use 1st param order'}]
)
the expected return value would be:
[ ['Length 2 Not Required', 8675309],
['Use 1st param order', 1]
]
I have written a code for this but my code does not return a list of lists, it just returns a single list. Please can someone explain?
def make_lists(s,lod):
a = []
lol =[]
i = 0
for x in lod:
for y in x:
for k in s:
if(y==k):
lol.append(x.get(y))
i = i+1
return lol
Expected Output:
[ ['Length 2 Not Required', 8675309],['Use 1st param order', 1] ]
Output:
['Length 2 Not Required', 8675309, 1, 'Use 1st param order']
The whole point of dictionaries, is that you can access them by key:
def make_lists(keys, dicts):
result = []
for d in dicts:
vals = [d[k] for k in keys if k in d]
if len(vals) > 0:
result.append(vals)
return result
Let's have a look what happens here:
We still have the result array, which accumulates the answers, but now it's called result instead of lol
Next we iterate through every dictionary:
for d in dicts:
For each dictionary d, we create a list, which is a lookup in that dictionary for the keys in keys, if the key k is in the dictionary d:
vals = [d[k] for k in keys if k in d]
The specs don't detail this, but I assume if none of the keys are in the dictionary, you don't want it added to the array. For that, we have a check if vals have any results, and only then we add it to the results:
if len(vals) > 0:
result.append(vals)
Try this code - I've managed to modify your existing code slighty, and added explanation in the comments. Essentially, you just need to use a sub-list and add that to the master list lol, and then in each loop iteration over elements in lod, append to the sub-list instead of the outermost list.
def make_lists(s,lod):
a = []
lol =[]
i = 0
for x in lod:
## Added
# Here we want to create a new list, and add it as a sub-list
# within 'lol'
lols = []
lol.append(lols)
## Done
for y in x:
for k in s:
if(y==k):
# Changed 'lol' to 'lols' here
lols.append(x.get(y))
i = i+1
return lol
print(make_lists(['Example'], [{'Example': 'Made-up', 'Extra Keys' : 'Possible'}]))
print(make_lists(['Hint', 'Num'], [{'Hint': 'Length 2 Not Required', 'Num' : 8675309}, {'Num': 1, 'Hint' : 'Use 1st param order'}]))
Prints:
[['Made-up']]
[['Length 2 Not Required', 8675309], [1, 'Use 1st param order']]
A simpler solution
For a cleaner (and potentially more efficient approach), I'd suggest using builtins like map and using a list comprehension to tackle this problem:
def make_lists(s, lod):
return [[*map(dict_obj.get, s)] for dict_obj in lod]
But note, that this approach includes elements as None in cases where the desired keys in s are not present in the dictionary objects within the list lod.
To work around that, you can pass the result of map to the filter builtin function so that None values (which represent missing keys in dictionaries) are then stripped out in the result:
def make_lists(s, lod):
return [[*filter(None, map(dict_obj.get, s))] for dict_obj in lod]
print(make_lists(['Example'], [{'Extra Keys' : 'Possible'}]))
print(make_lists(['Hint', 'Num'], [{'Num' : 8675309}, {'Num': 1, 'Hint' : 'Use 1st param order'}]))
Output:
[[]]
[[8675309], ['Use 1st param order', 1]]
I have tried this, for some unknown reason when it prints h, it prints None, so i thought if it counts the number of None printed then divided by 2 it will give the number of duplicates, but i cant use function count here
a= [1,4,"hii",2,4,"hello","hii"]
def duplicate(L):
li=[]
lii=[]
h=""
for i in L:
y= L.count(i)
if y>1:
h=y
print h
print h.count(None)
duplicate(a)
Use the Counter container:
from collections import Counter
c = Counter(['a', 'b', 'a'])
c is now a dictionary with the data: Counter({'a': 2, 'b': 1})
If you want to get a list with all duplicated elements (with no repetition), you can do as follows:
duplicates = filter(lambda k: c[k] > 1, c.iterkeys())
If you want to only count the duplicates, you can then just set
duplicates_len = len(duplicates)
You can use a set to get the count of unique elements, and then compare the sizes - something like that:
def duplicates(l):
uniques = set(l)
return len(l) - len(uniques)
i found an answer which is
a= [1,4,"hii",2,4,"hello",7,"hii"]
def duplicate(L):
li=[]
for i in L:
y= L.count(i)
if y>1:
li.append(i)
print len(li)/2
duplicate(a)
the answer by egualo is much better, but here is another way using a dictionary.
def find_duplicates(arr):
duplicates = {}
duplicate_elements = []
for element in arr:
if element not in duplicates:
duplicates[element] = False
else:
if duplicates[element] == False:
duplicate_elements.append(element)
duplicates[element] = True
return duplicate_elements
It's pretty simple and doesn't go through the lists twice which is kind of nice.
>> test = [1,2,3,1,1,2,2,4]
>> find_duplicates(test)
[1, 2]
I have List of dictionaries like:
Stock=[
{'ID':1,'color':'red','size':'L','material':'cotton','weight':100,'length':300,'location':'China'},
{'ID':2,'color':'green','size':'M','material':'cotton','weight':200,'length':300,'location':'China'},
{'ID':3,'color':'blue','size':'L','material':'cotton','weight':100,'length':300,'location':'China'}
]
And other list of dictionaries like:
Prices=[
{'color':'red','size':'L','material':'cotton','weight':100,'length':300,'location':'China'}
{'color':'blue','size':'S','weight':500,'length':150,'location':'USA', 'cost':1$}
{'color':'pink','size':'L','material':'cotton','location':'China','cost':5$},
{'cost':5$,'color':'blue','size':'L','material':'silk','weight':100,'length':300}
]
So I need find 'cost' for each record in Stock from Prices. But may be a situation, when I don't find 100% coincidence of dict elements, and in this case I need most similar element and get it's "cost".
output=[{'ID':1,'cost':1$},{'ID':2,'cost':5$},...]
Please, prompt the optimal solution for this task. I think it's like Loop from highest to lowest compliance, when we try find record with max coincidence, and if not found - try less matching condition.
how about this
Stock=[
{'ID':1,'color':'red','size':'L','material':'cotton','weight':100,'length':300,'location':'China'},
{'ID':2,'color':'green','size':'M','material':'cotton','weight':200,'length':300,'location':'China'},
{'ID':3,'color':'blue','size':'L','material':'cotton','weight':100,'length':300,'location':'China'}
]
Prices=[
{'color':'red','size':'L','material':'cotton','weight':100,'length':300,'location':'China'},
{'cost':'2$','color':'blue','size':'S','weight':500,'length':150,'location':'USA'},
{'cost':'5$','color':'pink','size':'L','material':'cotton','location':'China'},
{'cost':'15$','color':'blue','size':'L','material':'silk','weight':100,'length':300}
]
Prices = [p for p in Prices if "cost" in p] #make sure that everything have a 'cost'
result = []
for s in Stock:
field = set(s.items())
best_match = max(Prices, key=lambda p: len( field.intersection(p.items()) ), default=None)
if best_match:
result.append( {"ID":s["ID"], "cost":best_match["cost"] } )
print(result)
#[{'ID': 1, 'cost': '5$'}, {'ID': 2, 'cost': '5$'}, {'ID': 3, 'cost': '15$'}]
to find the most similar entry I first transform the dict to a set then use max to find the largest intersection of a price with the stock that I'm checking using a lambda function for the key of max
it reminds me of fuzzy or neural network solutions,
[on python2]
anyway , here is a Numpy solution, :
Stock=[
{'ID':1,'color':'red','size':'L','material':'cotton','weight':100,'length':300,'location':'China'},
{'ID':2,'color':'green','size':'M','material':'cotton','weight':200,'length':300,'location':'China'},
{'ID':3,'color':'blue','size':'L','material':'cotton','weight':100,'length':300,'location':'China'}
]
Prices=[
{'color':'red','size':'L','material':'cotton','weight':100,'length':300,'location':'China'},
{'cost':2,'color':'blue','size':'S','weight':500,'length':150,'location':'USA'},
{'cost':5,'color':'pink','size':'L','material':'cotton','location':'China'},
{'cost':15,'color':'blue','size':'L','material':'silk','weight':100,'length':300}
]
import numpy as np
# replace non useful records.
for p in Prices:
if not(p.has_key('cost')):
Prices.remove(p)
def numerize(lst_of_dics):
r=[]
for d in lst_of_dics:
r1=[]
for n in ['color','size','material','weight','length','location']:
try:
if n=='color':
# it is 0s if unknown
# only 3 letters, should work ,bug!!!
z=[0,0,0]
r1+=[ord(d[n][0]),ord(d[n][1]),ord(d[n][2])]
elif n=='size':
z=[0,0,0]
r1+=[ord(d[n])]*3
elif n=='material':
z=[0,0,0]
r1+=[ord(d[n][0]),ord(d[n][1]),ord(d[n][2])]
elif n=='location':
z=[0,0,0]
r1+=[ord(d[n][0]),ord(d[n][1]),ord(d[n][2])]
else:
z=[0,0,0]
r1+=[d[n]]*3
except:
r1+=z
r.append(r1)
return r
St = numerize(Stock)
Pr = np.array(numerize(Prices))
output=[]
for i,s in enumerate(St):
s0 = np.reshape(s*Pr.shape[0],Pr.shape)
# stage 0: make one element array to subtract easily
s1 = abs(Pr -s0)
# abs diff
s2 = s1 * Pr.astype('bool') * s0.astype('bool')
# non-extentent does'nt mean match..
s21 = np.logical_not(Pr.astype('bool') * s0.astype('bool'))*25
s2 = s2+s21
# ignore the zero fields..(non-extentse)
s3 = np.sum(s2,1)
# take the smallest
s4 = np.where(s3==np.min(s3))[0][0]
c = Prices[s4]['cost']
#print c,i
output.append( {'ID':i+1 ,'cost':c})
print(output)
that gives me the next results (with many assumptions):
[{'cost': 15, 'ID': 1}, {'cost': 5, 'ID': 2}, {'cost': 15, 'ID': 3}]
Note, that this is correct comparison result based on Values and Kinds of properties
please up vote and check the answer if it satisfies you..
I have the following 2 lists in python:
ll = [500,500,500,501,500,502,500]
mm = [499,501,502]
I want to find out the position of last occurence of any item in mm, in the list ll. I can do this for a single element like this:
len(ll) - 1 - ll[::-1].index(502)
>> 5
Here ll[::-1].index(502) provides position of last occurence of 502 and len(ll) - 1 gives the total length.
How do I extend this to work for the entire list mm? I know I can write a function, but is there a more pythonic way
If you want all the last indices of each item in ll present in mm, then:
ll = [500,500,500,501,500,502,500]
mm = [499,501,502]
d = {v:k for k,v in enumerate(ll) if v in mm}
# {501: 3, 502: 5}
It's probably worth creating a set from mm first to make it an O(1) lookup, instead of O(N), but for three items, it's really not worth it.
Following #Apero's concerns about retaining missing indices as None and also using a hash lookup to make it an O(1) lookup...
# Build a key->None dict for all `mm`
d = dict.fromkeys(mm)
# Update `None` values with last index using a gen-exp instead of dict-comp
d.update((v,k) for k,v in enumerate(ll) if v in d)
# {499: None, 501: 3, 502: 5}
results = {}
reversed = ll[::-1]
for item in mm:
try:
index = ((len(ll) - 1) - reversed.index(item))
except ValueError:
index = None
finally:
results[item] = index
print results
Output:
{499: None, 501: 3, 502: 5}
You can do this with a list comprehension and the max function. In particular, for each element in ll, iterate through mm to create a list of indices where ll[i] = mm[i], and take the max of this list.
>>> indices = [ max([-1] + [i for i, m in enumerate(mm) if m == n]) for n in ll ]
>>> indices
[-1, -1, -1, 1, -1, 2, -1]
Note that you need to add [-1] in case there are no matching indices in mm.
All this being said, I don't think it's more Python-ic than writing a function and using a list comprehension (as you alluded to in your question).
I want to append several variables to a list. The number of variables varies. All variables start with "volume". I was thinking maybe a wildcard or something would do it. But I couldn't find anything like this. Any ideas how to solve this? Note in this example it is three variables, but it could also be five or six or anything.
volumeA = 100
volumeB = 20
volumeC = 10
vol = []
vol.append(volume*)
You can use extend to append any iterable to a list:
vol.extend((volumeA, volumeB, volumeC))
Depending on the prefix of your variable names has a bad code smell to me, but you can do it. (The order in which values are appended is undefined.)
vol.extend(value for name, value in locals().items() if name.startswith('volume'))
If order is important (IMHO, still smells wrong):
vol.extend(value for name, value in sorted(locals().items(), key=lambda item: item[0]) if name.startswith('volume'))
Although you can do
vol = []
vol += [val for name, val in globals().items() if name.startswith('volume')]
# replace globals() with locals() if this is in a function
a much better approach would be to use a dictionary instead of similarly-named variables:
volume = {
'A': 100,
'B': 20,
'C': 10
}
vol = []
vol += volume.values()
Note that in the latter case the order of items is unspecified, that is you can get [100,10,20] or [10,20,100]. To add items in an order of keys, use:
vol += [volume[key] for key in sorted(volume)]
EDIT removed filter from list comprehension as it was highlighted that it was an appalling idea.
I've changed it so it's not too similar too all the other answers.
volumeA = 100
volumeB = 20
volumeC = 10
lst = map(lambda x : x[1], filter(lambda x : x[0].startswith('volume'), globals().items()))
print lst
Output
[100, 10, 20]
do you want to add the variables' names as well as their values?
output=[]
output.append([(k,v) for k,v in globals().items() if k.startswith('volume')])
or just the values:
output.append([v for k,v in globals().items() if k.startswith('volume')])
if I get the question appropriately, you are trying to append different values in different variables into a list. Let's see the example below.
Assuming :
email = 'example#gmail.com'
pwd='Mypwd'
list = []
list.append(email)
list.append (pwd)
for row in list:
print(row)
# the output is :
#example#gmail.com
#Mypwd
Hope this helps, thank you.