How to search/append a list within a dictionary - python

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

Remove duplicate key, values from a dictionary such that each key or value appear only once

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()))}

How do I find each duplicate's index in a List in Python?

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]

Match dictionary keys and values in new dictionary

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]}

Sum tuples of cartesian product of arbitrary number of dicts

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]}

Summation of elements of dictionary that are list of lists

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

Categories

Resources