Say I have a dictionary comprised of integer keys, and a list of integers corresponding to each key.
myDict = {0:[1,2,3,4], 1:[1,2,3], 2:[3,4,5]}
How do I search the list in key 1 for the integer 4, and if it's not in the list append it so that 1:[1,2,3,4]
Try this:
myDict = {0:[1,2,3,4], 1:[1,2,3], 2:[3,4,5]}
# Only if k exists in 'dict'. We append value for that specific key
def search_append(d, k, v):
if (k in d) and (not v in d[k]):
d[k].append(v)
search_append(myDict, 1, 4)
print(myDict)
{0: [1, 2, 3, 4], 1: [1, 2, 3, 4], 2: [3, 4, 5]}
# if k is not in 'dict' we create a key and append the value
def search_append_2(d, k, v):
if not v in d.get(k, []):
d.setdefault(k, []).append(v)
search_append_2(myDict, 3, 4)
print(myDict)
# {0: [1, 2, 3, 4], 1: [1, 2, 3], 2: [3, 4, 5], 3: [4]}
Related
I have a python dictionary which contains multiple key,values which are actually image indexes. For e.g. the dictionary I have looks something as given below
{
1: [1, 2, 3],
2: [1, 2, 3],
3: [1, 2, 3],
4: [4, 5],
5: [4, 5],
6: [6]
}
this means that 1 is related to 1, 2 & 3. Similarly 2 is related to 1, 2 & 3. 6 has only 6 in it so it's related to none of the other elements. This is leading me to perform extra operations in my programs. I want the dictionary to be filtered and look like
# Preferred output
{
1: [2, 3],
4: [5],
6: []
}
So far I have tried
new_dict = dict()
# source is the original dictionary
for k,v in source.items():
ok = True
for k1,v1 in new_dict.items():
if k in v1: ok = False
if ok: new_dict[k] = v
This modifies the dictionary to
{1: [1, 2, 3], 4: [4, 5], 6: [6]}
I am looking for a more efficient and pythonic way to solve this problem.
This shows the preferred output:
source = {
1: [1, 2, 3],
2: [1, 2, 3],
3: [1, 2, 3],
4: [4, 5],
5: [4, 5],
6: [6]
}
new_dict = {}
seen = set()
for k, v in source.items():
if k in seen: continue
seen.add(k)
new_v = [i for i in v if i not in seen]
seen.update(new_v)
new_dict[k] = new_v
print(new_dict)
How about this, use my modification below to remove the first item in the list during each loop. I commented the line which does it.
new_dict = dict()
# source is the original dictionary
for k,v in source.items():
ok = True
for k1,v1 in new_dict.items():
if k in v1: ok = False
if ok: new_dict[k] = v[1:] #this line removes the first element.
My output is,
{1: [2, 3], 4: [5], 6: []}
your modified code:
ver 1:
new_dict = dict()
for k, v in source.items():
if not any(k in v1 for v1 in new_dict.values()):
new_dict[k] = v[1:]
ver 2:
tmp = dict()
for k, v in source.items():
tmp[tuple(v)] = tmp.get(tuple(v), []) + [k]
res = dict()
for k, v in tmp.items():
res[v[0]] = v[1:]
ver 3:
new_dict = {v[0]: list(v[1:]) for v in set(map(tuple, source.values()))}
For example, let's say I have a list:
lst = [1, 2, 3, 3, 4, 3, 5, 6]
Is there any function that returns all the indexes of the 3s?(which would return [2, 3, 5])
I've changed the list in order to build a dictionary of all items that appeared more than once.
from collections import Counter
lst = [1, 2, 3, 3, 4, 3, 5, 2, 6]
# only values that appears more than once
c = Counter(lst) - Counter(set(lst))
res = {}
for i, elem in enumerate(lst):
if elem in c:
item = res.get(elem)
if item:
item.append(i)
else:
res[elem] = [i]
print(res)
output :
{2: [1, 7], 3: [2, 3, 5]}
A better approach is to use defaultdict :
from collections import defaultdict
lst = [1, 2, 3, 3, 4, 3, 5, 2, 6]
d = defaultdict(list)
for i, elem in enumerate(lst):
d[elem].append(i)
print({k: v for k, v in d.items() if len(v) > 1})
output :
{2: [1, 7], 3: [2, 3, 5]}
You can simply use function enumerate(lst)
it returns elements index_number and value.
for example
lst[0] = 1
the case above index_number is 0
and value is 1
so you can just use enumerate function for returning index number using if condition
(returns it when the value is 3)
lst = [1, 2, 3, 3, 4, 3, 5, 6]
lst_result = [i for i, v in enumerate(lst) if v == 3]
print(lst_result)
your outcome will be
[2,3,5]
I was trying to figure out a solution for a similar problem and this is what I came up with.
def locate_index(item_name, list_name):
"""Determine the indexes of an item if in a list."""
locations = []
for i in range(len(list_name)):
if list_name[i] == item_name:
locations.append(list_name.index(item_name, i, len(list_name)))
print(locations)
Example:
lst = [1, 2, 3, 3, 4, 3, 5, 6]
list2 = [1, 2, 3, 3, 4, 3, 5, 6, 6, 6, 6]
locate_index(3, lst) ---- a)
locate_index(6, list2) ---- b)
Output
a)
[2, 3, 5]
b)
[7, 8, 9, 10]
I trying to match keys and values in a dictionary together and put them into a new dictionary.
My initial dictionary looks like this:
d = {1: [5,6], 3: [4], 8: [2,3]}
I know that I can access keys and values using d.keys() and d.values().
My goal is to find all items which relate. I think it is best explained if I illustrate my desired output.
I wish to create a new dict that gives me:
finaldict = {1: [5,6], 2: [3,4,8], 3: [2,4,8], 4:[2,3,8] 5:[1,6], 6:[1,5], 8:[2,3,4]}
That is, I want to get keys of all numbers, and give values to what number they are related to.
My attempt:
d = {1: [5,6], 3:[4],8:[2,3]}
print(d)
keys = list(d.keys())
vals = list(d.values())
for i in range(0,len(d.keys())):
current_vals = list(vals[i])
length = len(current_vals)
for v in current_vals:
if v in d.keys(): #if the dictionary exists, then append
add = [keys[i],current_vals]
d[v].append(add)
else:
add2 = [keys[i],current_vals]
empty = []
for a in add2:
if type(a) == int:
empty.append(a)
if type(a) == list:
for b in a:
empty.append(b)
d[v] = empty
keys = list(d.keys())
vals = list(d.values())
for i in range(0,len(keys)):
if keys[i] in vals[i]:
vals[i].remove(keys[i])
finaldict = {}
for j in range(0,len(keys)):
finaldict[keys[j]] = vals[j]
print("Final dict:\n",finaldict)
My attempt gives me the output
Final dict:
{1: [5, 6], 3: [4, [8, [2, 3]]], 8: [2, 3], 5: [1, 6], 6: [1, 5], 4: [3], 2: [8, 3]}
As you can see, finaldict[3] has the values [4, [8, [2, 3,]]].
The values themselves are wrong (3 should not be there), and also I want this to be a single list, and not on the format it is now. There are also other issues, such as finaldict[2] having the values [8, 3] when it should, in fact, have the values [3, 4, 8] and finaldict[4] only having [3], when it should have [2, 3, 8].
Not the most beautiful code I've ever written, but here it goes.
I create sets with all the numbers that are related to each other, then create a dictionary of each of those numbers as key, with the other ones as values.
d = {1: [5,6], 3: [4], 8: [2,3]}
pools = []
for key,values in d.items():
for pool in pools:
if key in pool or any(val in pool for val in values):
pool.add(key)
[pool.add(val) for val in values]
break
else:
pools.append(set((key, *values)))
#pools = [{1, 5, 6}, {8, 2, 3, 4}]
finaldict = {k:set.difference(v, set((k,))) for pool in pools for k, v in zip(pool, [pool]*len(pool))}
print(finaldict)
You can use recursion:
d = {1: [5,6], 3: [4], 8: [2,3]}
def groups(v, seen = [], c = []):
if (k:=[i for a, b in d.items() for i in ({a, *b} if v in {a, *b} else []) if i not in {*seen, v}]):
for i in k:
yield from groups(i, seen=seen+[v], c = c+([v] if seen else []))
else:
yield c+[v]
r = {i:[*{j for k in groups(i) for j in k}] for a, b in d.items() for i in [a, *b]}
Output:
{1: [5, 6], 5: [1, 6], 6: [1, 5], 3: [8, 2, 4], 4: [8, 2, 3], 8: [2, 3, 4], 2: [8, 3, 4]}
You can build up the resulting dictionary by merging related groups and assigning the same merged group to every key that is part of it:
d = {1: [5,6], 3: [4], 8: [2,3]}
related = dict()
for key,group in d.items(): # merge/assign groups to keys
merged = set(group).union({key},*(related.get(k,[]) for k in group))
related.update((k,merged) for k in merged)
related = {k:list(g-{k}) for k,g in related.items()} # exclude key from group
print(related)
{1: [5, 6], 5: [1, 6], 6: [1, 5], 3: [8, 2, 4], 4: [8, 2, 3],
2: [8, 3, 4], 8: [2, 3, 4]}
I'd like to do the cartesian product of multiple dicts, based on their keys, and then sum the produced tuples, and return that as a dict. Keys that don't exist in one dict should be ignored (this constraint is ideal, but not necessary; i.e. you may assume all keys exist in all dicts if needed). Below is basically what I'm trying to achieve (example shown with two dicts). Is there a simpler way to do this, and with N dicts?
def doProdSum(inp1, inp2):
prod = defaultdict(lambda: 0)
for key in set(list(inp1.keys())+list(inp2.keys())):
if key not in prod:
prod[key] = []
if key not in inp1 or key not in inp2:
prod[key] = inp1[key] if key in inp1 else inp2[key]
continue
for values in itertools.product(inp1[key], inp2[key]):
prod[key].append(values[0] + values[1])
return prod
x = doProdSum({"a":[0,1,2],"b":[10],"c":[1,2,3,4]}, {"a":[1,1,1],"b":[1,2,3,4,5]})
print(x)
Output (as expected):
{'c': [1, 2, 3, 4], 'b': [11, 12, 13, 14, 15], 'a': [1, 1, 1, 2, 2, 2,
3, 3, 3]}
You can do it like this, by first reorganizing your data by key:
from collections import defaultdict
from itertools import product
def doProdSum(list_of_dicts):
# We reorganize the data by key
lists_by_key = defaultdict(list)
for d in list_of_dicts:
for k, v in d.items():
lists_by_key[k].append(v)
# list_by_key looks like {'a': [[0, 1, 2], [1, 1, 1]], 'b': [[10], [1, 2, 3, 4, 5]],'c': [[1, 2, 3, 4]]}
# Then we generate the output
out = {}
for key, lists in lists_by_key.items():
out[key] = [sum(prod) for prod in product(*lists)]
return out
Example output:
list_of_dicts = [{"a":[0,1,2],"b":[10],"c":[1,2,3,4]}, {"a":[1,1,1],"b":[1,2,3,4,5]}]
doProdSum(list_of_dicts)
# {'a': [1, 1, 1, 2, 2, 2, 3, 3, 3],
# 'b': [11, 12, 13, 14, 15],
# 'c': [1, 2, 3, 4]}
d = {
'a': [[1, 2, 3], [1, 2, 3]],
'b': [[2, 4, 1], [1, 6, 1]],
}
def add_element(lst):
ad = [sum(i) for i in zip(*lst)]
return ad
def csv_reducer2(dicty):
return {k: list(map(add_element, v)) for k, v in dicty.items()}
csv_reducer2(d)
required output:
{'b': [3, 10, 2], 'a': [2, 4, 6]}
Above is the code I have been trying but it gives an error
zip argument #1 must support iteration
>>> d = {'a': [[1, 2, 3], [1, 2, 3]], 'b': [[2, 4, 1], [1, 6, 1]]}
>>> {k: map(sum, zip(*v)) for k, v in d.items()}
{'a': [2, 4, 6], 'b': [3, 10, 2]}
The following will work on Python 2 or 3:
>>> {k: [a + b for a, b in zip(*v)] for k, v in d.items()}
{'a': [2, 4, 6], 'b': [3, 10, 2]}
The issue with your code is you are mapping add_element to every individual element in v inside your dictionary comprehension. This passes a one-dimensional list to zip in add_element, resulting in your error (since individual integers don't support iteration.
To fix your original code, the only change you need to make is:
return {k: list(map(add_element, v)) for k, v in dicty.items()}
->
return {k: add_element(v) for k, v in dicty.items()}
Because zip(*lst) is trying to transpose multiple rows into columns, but you are only passing it single rows through your original map