Finding Index in string with recurring chars - python

I have string a='51545'
I am finding index of the each char in the string like this
modchar=[{i:a.index(i)} for i in a ]
#modchar=[{'5': 0}, {'1': 1}, {'5': 0}, {'4': 3}, {'5': 0}]
but i need to get it as
#modchar=[{'5': 0}, {'1': 1}, {'5': 2}, {'4': 3}, {'5': 4}]
How can we achieve this?

In this case, you probably want to enumerate the string creating the dictionaries as you go:
[{c: i} for i, c in enumerate(a)]
Note that as a side bonus, this happens in O(n) time opposed to your original solution which is O(n^2)

Try this:
a='51545'
obj = []
for i in range(len(a)):
obj.append({a[i]: i})
This runs as:
>>> a='51545'
>>> obj = []
>>> for i in range(len(a)):
... obj.append({a[i]: i})
...
>>> obj
[{'5': 0}, {'1': 1}, {'5': 2}, {'4': 3}, {'5': 4}]
>>>
You can do list comprehension using enumerate:
[{value: index} for value, index in enumerate(a)]
Which runs as:
>>> [{value: index} for index, value in enumerate(a)]
[{'5': 0}, {'1': 1}, {'5': 2}, {'4': 3}, {'5': 4}]
>>>
Or, you can use a basic list comprehension:
[{a[index]: index} for index in range(len(a))]
Which runs as:
>>> [{a[index]: index} for index in range(len(a))]
[{'5': 0}, {'1': 1}, {'5': 2}, {'4': 3}, {'5': 4}]
>>>
enumerate is basically a combination of using a for loop to get the index, and then accessing the list:
>>> arr = [5, 8, 2, 4]
>>> for index, value in enumerate(arr):
... print index, value
...
0 5
1 8
2 2
3 4
>>>

Related

why i can't get the result of appending list in python

d={}
for i in range (5):
d['key']=i
lst.append(d)
print(lst)
>>>[{'key': 4}, {'key': 4}, {'key': 4}, {'key': 4}, {'key': 4}]
Why i didn't got this result plz :>>>[{'key': 0}, {'key': 1}, {'key': 2}, {'key': 3}, {'key': 4}] ?
This code will work:
lst = []
for i in range(1, 6):
lst.append({"key", i})
print(lst)
The problem was that you are appending the variable d to lst. the value of lst is now [d, d, d, d, d]. When printing, this evaluates to d's current value, which happens to be {'key', 4}. My code appends the value of d to the list without creating d. This is at least my interpretation of this. Could be wrong.

Merge Dictionaries oin a list with the same key

I have a list of dicts, like this:
x = [{'a': 3}, {'b': 1}, {None: 0}, {'a': 1}, {'b': 1}, {None: 0}]
and I would like to have a something like this
x = [{'a': 4}, {'b': 2}, {None: 0}]
What is the most memory-friendly way to reach that?
You can also use collections.Counter, which will naturally update the counts:
from collections import Counter
l = [{'a': 3}, {'b': 1}, {None: 0}, {'a': 1}, {'b': 1}, {None: 0}]
counts = Counter()
for d in l:
counts.update(d)
print([{k: v} for k, v in counts.items()])
From the docs for collections.Counter.update:
Elements are counted from an iterable or added-in from another mapping (or counter). Like dict.update() but adds counts instead of replacing them. Also, the iterable is expected to be a sequence of elements, not a sequence of (key, value) pairs.
You can also use a collections.defaultdict to do the counting:
from collections import defaultdict
l = [{'a': 3}, {'b': 1}, {None: 0}, {'a': 1}, {'b': 1}, {None: 0}]
counts = defaultdict(int)
for d in l:
for k, v in d.items():
counts[k] += v
print([{k: v} for k, v in counts.items()])
Or you could also count with initializing 0 yourself:
l = [{'a': 3}, {'b': 1}, {None: 0}, {'a': 1}, {'b': 1}, {None: 0}]
counts = {}
for d in l:
for k, v in d.items():
counts[k] = counts.get(k, 0) + 1
print([{k: v} for k, v in counts.items()])
From the docs for dict.get:
Return the value for key if key is in the dictionary, else default. If default is not given, it defaults to None, so that this method never raises a KeyError.
Output:
[{'a': 4}, {'b': 2}, {None: 0}]
Lets say:
l = [{'a': 3}, {'b': 1}, {None: 0}, {'a': 1}, {'b': 1}, {None: 0}]
Now we will extract and add up:
res = []
for k in l:
for i in k:
s = {i:sum(j[i] for j in l if i in j)}
if s not in res:
res.append(s)
gives:
[{'a': 4}, {'b': 2}, {None: 0}]
Or we could use (adapted from here ):
result = {}
for d in l:
for k in d.keys():
result[k] = result.get(k, 0) + d[k]
res = [{i:result[i]} for i in result]
Check the one-line code using pandas.
L = [{'a': 3}, {'b': 1}, {None: 0}, {'a': 1}, {'b': 1}, {None: 0}]
output = pd.DataFrame(L).sum(axis = 0).to_dict()

How to update list recursively

I have a list of dicts:
a = [{'one': 1}, {'two': 2}, {'three': 3}, {'four': 4}, {'five': 5}]
I want to update the value of each element in this list by the sum of all remainders. (so 'one' will get the value 2+3+4+5) .
so that it will look like this:
a = [{'one': 14}, {'two': 12}, {'three': 9}, {'four': 5}, {'five': 5}]
'five' is the last, so it will not update .
Im not sure how to achieve this. Im thinking that you construct a function that will call itself recursivly something like:
def recursive(a):
if len(a) == 1:
return list(a[0].values())[0]
else:
val = list(a[0].values())[0]
return val + recursive(a.pop(0))
But Im not sure to do this list(a[0].values())[0] is the "best" way. And this is also getting a KeyError: 0.
Any ideas?
Iterative and in place solution
a = [{'one': 1}, {'two': 2}, {'three': 3}, {'four': 4}, {'five': 5}]
sum_so_far = 0
first_flag = False
for i in a[::-1]:
k,v = i.items()[0] #For Python 3 k,v = list(i.items())[0]
sum_so_far += v
if first_flag:
i[k] = sum_so_far # do not change the value at first
first_flag=True
Output
[{'one': 15}, {'two': 14}, {'three': 12}, {'four': 9}, {'five': 5}]
Your problem comes from the output of a.pop(0). A.pop(0) returns the element at 0, not the list without the element at 0. Therefore, when you call recursively, you are indexing on a dict, rather than a list. What do you expect to be inputting into the recursive call?
I would guess you are trying to remove the 0th index, then call recursively. To do this,
a.pop(0);
return val + recursive(a)
edit: a note - key error 0 means you are indexing a dict with key 0 when key 0 does not yet exist.
A possible recursive solution:
d = [{'one': 1}, {'two': 2}, {'three': 3}, {'four': 4}, {'five': 5}]
def sums(data, _sum = 0):
a, *b = data
if not b:
return [a], list(a.values())[0]
c, _d = sums(b, _sum+list(a.values())[0])
return [{list(a.keys())[0]:_d}, *c], _d+list(a.values())[0]
result, _ = sums(d)
Output:
[{'one': 14}, {'two': 12}, {'three': 9}, {'four': 5}, {'five': 5}]
Quick and dirty one liner...
[{list(d.keys())[0]: sum(list(v.values())[0] for v in a[i + (1 if i<len(a)-1 else 0):])} for i, d in enumerate(a)]
# [{'one': 14}, {'two': 12}, {'three': 9}, {'four': 5}, {'five': 5}]

Remove duplicate dictionaries from a list and subtract value of keys of duplicate element

I have a list of dicts, and I'd like to remove the dicts with identical key and subtract the value pairs.
For this list:
[{'chair': 4}, {'tv': 5}, {'chair': 3}, {'tv': 2}, {'laptop': 2}]
I'd like to return this:
[{'chair': 1}, {'tv': 3}, {'laptop': 2}]
You could do it like this, creating an intermediate dict for efficiency:
dicts_list = [{'chair': 4}, {'tv': 5}, {'chair': 3}, {'tv': 2}, {'laptop': 2}]
out = {}
for d in dicts_list:
for key, val in d.items():
if key in out:
out[key] -= val
else:
out[key] = val
out_list = [ {key:val} for key, val in out.items()]
print(out_list)
# [{'tv': 3}, {'chair': 1}, {'laptop': 2}]
But you might be interested in this intermediate dict as output:
print(out)
# {'tv': 3, 'chair': 1, 'laptop': 2}
defaultdict from collections might come in handy. This solution will cover the cases where there are more than 2 dicts of the same key in the list.
from collections import defaultdict
ls = defaultdict(list)
d = [{'chair': 4}, {'tv': 5}, {'chair': 3}, {'tv': 2}, {'laptop': 2}]
# Creating a list of all values under one key
for dic in d:
for k in dic:
ls[k].append(dic[k])
print(ls)
defaultdict(<class 'list'>, {'chair': [4, 3], 'tv': [5, 2], 'laptop': [2]})
# safe proofing for negative values on subtraction
for k in ls:
ls[k].sort(reverse=True)
ls[k] = ls[k][0] - sum(ls[k][1:])
print(ls)
defaultdict(<class 'list'>, {'chair': 1, 'tv': 3, 'laptop': 2})
You can construct a defaultdict of lists, then use a list comprehension:
from collections import defaultdict
dd = defaultdict(list)
for d in data:
k, v = next(iter(d.items()))
dd[k].append(v)
res = [{k: v if len(v) == 1 else v[0] - sum(v[1:])} for k, v in dd.items()]
print(res)
# [{'chair': 1}, {'tv': 3}, {'laptop': [2]}]
Following snippet is using nothing but standard modules:
a= [{'chair': 4}, {'tv': 5}, {'chair': 3}, {'tv': 2}, {'laptop': 2}]
print("Input:", a)
b=dict()
for element in a:
for k,v in element.items():
try:
# you didn't specify the subtracted element order,
# so I'm subtracting BIGGER from SMALLER using simple abs() :)
b[k] = abs(b[k] - v)
except:
b[k] = v
print("Output:", b)
# restore original structure
c = [ dict({item}) for item in b.items() ]
print("Output:", c)
And demo:
('Input:', [{'chair': 4}, {'tv': 5}, {'chair': 3}, {'tv': 2}, {'laptop': 2}])
('Output:', {'tv': 3, 'chair': 1, 'laptop': 2})
('Output:', [{'tv': 3}, {'chair': 1}, {'laptop': 2}])
EDIT: Added the secondary out put C to restructure B similar to A

Dynamically join of dictionary

a="90342"
# this used to generate a dict of each char in a and it indexs
modchar=[{i:a.index(i)} for i in a ]
#modchar=[{'9': 0}, {'0': 1}, {'3': 2}, {'4': 3}, {'2': 4}]
# below produce combination now this combination
def combination(x,n):
return list(itertools.combinations(x,n))
combination(modchar,1)
#output [({'9': 0},), ({'0': 1},), ({'3': 2},), ({'4': 3},), ({'2': 4},)]
combination(modchar,2)
#output [({'9': 0}, {'0': 1}), ({'9': 0}, {'3': 2}), ({'9': 0}, {'4': 3}), ({'9': 0}, {'2': 4}), ({'0': 1}, {'3': 2}), ({'0': 1}, {'4': 3}), ({'0': 1}, {'2': 4}), ({'3': 2}, {'4': 3}), ({'3': 2}, {'2': 4}), ({'4': 3}, {'2': 4})]
combination(modchar,3)
#output [({'9': 0}, {'0': 1}, {'3': 2}), ({'9': 0}, {'0': 1}, {'4': 3}), ({'9': 0}, {'0': 1}, {'2': 4}), ({'9': 0}, {'3': 2}, {'4': 3}),....]
if u look at each result in the list first element is tuple of dict.what i want to do is to combine the dictionary inside the tuple and make it as single dict
i have tried
map(lambda x:dict(x[0],**x[1]),list(itertools.combinations(x,n)))
above works only for tuple of two dicts.
how can i produce a code dynamically it should combine all dicts and produce single dict irrespictive of n value in combination(x,n)
expected output: for n=2
[({'9': 0,'0': 1}) ....]
expected output: for n=3
[({'9': 0,'0': 1,'3': 2})..]
Here's a way to do it:
combos = combinations(modchar,3)
def combineDictTuple(dt):
d = {}
for item in dt:
d.update(item)
return d
newCombos = [combineDictTuple(dt) for dt in combos]
# OUTPUT: [{'9': 0, '0': 1, '3': 2}, {'9': 0, '0': 1, '4': 3}, {'9': 0, '0': 1, '2': 4}, {'9': 0, '3': 2, '4': 3}, {'9': 0, '3': 2, '2': 4}, {'9': 0, '2': 4, '4': 3}, {'0': 1, '3': 2, '4': 3}, {'0': 1, '3': 2, '2': 4}, {'0': 1, '2': 4, '4': 3}, {'3': 2, '2': 4, '4': 3}]
This should do what you want:
>>> def update_with_return(d1, d2):
... d1.update(d2)
... return d1
...
>>> reduce(update_with_return, ({'a': 1}, {'b':2}), dict())
{'a': 1, 'b': 2}

Categories