I have a dictionary of lists:
g = {'a': ['b', 'c'], 'b': ['a', 'd', 'e']}
in which some of the values are not present as keys. I want to add all values, as keys with empty lists, which are not present in keys. Current I am attempting to do this as follows:
for keys, values in g.items():
for value in values:
if value not in keys:
g[value] = []
Running the above code gives a traceback: RuntimeError: dictionary changed size during iteration. I checked other related questions in Stackoverflow but couldn't find a related task.
I look to have the following output:
{'a': ['b', 'c'], 'b': ['a', 'd', 'e'], 'c': [], 'd': [], 'e': []}
Solution
g = {'a': ['b', 'c'], 'b': ['a', 'd', 'e']}
for keys, values in list(g.items()):
for value in values:
if value not in g:
g[value] = []
print(g)
Explanation
Please refer to this Stack Overflow post for more information regarding using list(). Also, your conditional should check if value is in g, not in keys.
Related
I have a Pandas data frame, which looks like the following:
df =
col1
['a', 'b']
['d', 'c', 'a']
['b', 'f', 'a']
col1 is a list column, which contains strings. I want to calculate value counts of each element, which may occur in any of the lists in any row. Expected output is a dictionary, of counts of each value
Expected Output
df_dict = {'a': 3, 'b': 2, 'c': 1, 'd': 1, 'f': 1}
How to do this efficiently in 1 line preferably to make the code clean. Sorry, if it has been answered before.
With explode and value_counts:
df['col1'].explode().value_counts().to_dict()
Output:
{'a': 3, 'b': 2, 'd': 1, 'f': 1, 'c': 1}
im trying to build a nested dictionary based on 3 pandas df columns:
dataframe: stops
columns: 'direction' (1-2) ,'stop_num'(1-23 if the direction is 1 and 100-2300 if direction is 2),'name_eng'
what i was trying to do is:
dct = {x: {y:z} for x, y, z in zip(stops['direction'],stops['name_eng'],stops['stop_num'])}
the result i get is a nested dictionary indeed but for unknown reason i get only the last value in y:z so the dictionary look like:
{1:{1:'aaa'},'2:{100:'bbb'}}
any idea what am i doing wrong?
what i need is a nested dictionary with two dictionaries for each direction.
thanks!
Imagine your columns are:
1 a 1a
1 b 1b
2 a 2a
2 b 2b
Now, try your code:
>>> {x: {y:z} for x, y, z in zip([1,1,2,2], ['a', 'b', 'a', 'b'], ['1a', '1b', '2a', '2b'])}
{1: {'b': '1b'}, 2: {'b': '2b'}}
You have a loop over the tuples: (1, 'a', '1a'), (1, 'b', '1b'), (2, 'a', '2a'), (2, 'b', '2b').
The first element of the tuple is the "main" key of your dictionary. Thus, the dict is {1: {'a':'1a'}} after the first tuple.
Then comes (1, 'b', '1b'). The value of the main key 1 is overwritten and the dict becomes: {1: {'b':'1b'}}.
The next steps are: {1: {'b':'1b'}, 2: {'a': '2a'}} and {1: {'b': '1b'}, 2: {'b': '2b'}}
To avoid the overwrite, you can do:
>>> d = {}
>>> for x, y, z in zip([1,1,2,2], ['a', 'b', 'a', 'b'], ['1a', '1b', '2a', '2b']):
... d.setdefault(x, {}).update({y:z})
...
>>> d
{1: {'a': '1a', 'b': '1b'}, 2: {'a': '2a', 'b': '2b'}}
The idea is to create a new dict for every new main key (setdefault(..., {})) and to update the dict associated with the main key (update({y:z})).
If you want a dict comprehension, this one will work:
>>> {x: {y:z for k, y, z in zip([1,1,2,2], ['a', 'b', 'a', 'b'], ['1a', '1b', '2a', '2b']) if k==x} for x in set([1,1,2,2])}
{1: {'a': '1a', 'b': '1b'}, 2: {'a': '2a', 'b': '2b'}}
But it's far less efficient than the for loop because you loop once over the first column to get the main keys, then once again over all the rows, for every main key.
I try to add a list to a dictionary key, but when I append a value, it returns the value None. I have also tried collections.defaultdict(list) without success.
Code:
text = "ABBBAACCCCAABBCCCCAABCBCBCABCCCA"
chain = dict()
for i in range (0, text.__len__()-1):
key = text[i : i+1]
next_word = text[i +1 : i +2]
if key not in chain.keys():
chain.setdefault(key)
else:
chain.setdefault(key, [].append(next_word))
print(key, next_word, chain[key], chain)
Output:
A B None {'A': None}
B B None {'B': None, 'A': None}
B B None {'B': None, 'A': None}
B A None {'B': None, 'A': None}
…
[].append() returns None. You'd want to append to the return value of dict.setdefault() instead. You also don't need to do a key containment test when using dict.setdefault(); setdefault() already makes that test for you.
Next, don't call object.__len__(). Use len(object) instead. I'd also use {} instead of dict(); the latter has to look up a name and make a function call, the {} literal is compiled to a single bytecode to create a dictionary.
This works:
for i in range(len(text) - 1):
key = text[i:i + 1]
next_word = text[i + 1:i + 2]
chain.setdefault(key, []).append(next_word)
You could also use zip() to pair up the letters:
for key, next_word in zip(text, text[1:]):
chain.setdefault(key, []).append(next_word)
Demo:
>>> text = "ABBBAACCCCAABBCCCCAABCBCBCABCCCA"
>>> chain = {}
>>> for key, next_word in zip(text, text[1:]):
... chain.setdefault(key, []).append(next_word)
...
>>> chain
{'A': ['B', 'A', 'C', 'A', 'B', 'A', 'B', 'B'], 'B': ['B', 'B', 'A', 'B', 'C', 'C', 'C', 'C', 'C'], 'C': ['C', 'C', 'C', 'A', 'C', 'C', 'C', 'A', 'B', 'B', 'A', 'C', 'C', 'A']}
>>> from pprint import pprint
>>> pprint(chain)
{'A': ['B', 'A', 'C', 'A', 'B', 'A', 'B', 'B'],
'B': ['B', 'B', 'A', 'B', 'C', 'C', 'C', 'C', 'C'],
'C': ['C', 'C', 'C', 'A', 'C', 'C', 'C', 'A', 'B', 'B', 'A', 'C', 'C', 'A']}
I have a large number of identical lists 'old' which I want to transform in the same way into a list 'new'. The way I want to do it, is to make an example of the desired list 'new'. Then I turn the difference between the two lists 'old' and 'new' into a rule, and then use that rule to turn my other lists 'old_2' into 'new_2'.
I cannot figure out how to do the first step and the second step does not give me the expected result. Is there an elegant way to do this?
import numpy
# 0 1 2 3 4 5
old_1 = ['A', 'B', 'C', 'D', 'E', 'F']
new = ['B', 'C', 'D', 'E', 'A']
# 01 Get the difference new - /- old_1 based on index positions of
# the list elements, to get something like this:
order = [1,2,3,4,0]
# 02 Then use this order to transform a second identical list, old_2.
# For this I wanted to use the following:
old_2 = ['A', 'B', 'C', 'D', 'E', 'F']
old_2 = numpy.array(old_2)
order = numpy.array(order)
inds = order.argsort()
print('inds =', inds) # As a check, this gives the wrong order: [4 1 0 2 3]
new_2 = old_2[inds]
# I expected this to result in what I want, which is:
print(new_2)
['C', 'B', 'D', 'E', 'A']
# But what I get in reality is this:
inds = [4 1 0 2 3]
['E' 'B' 'A' 'C' 'D']
Any suggestions to get the desired result?
new_2 = ['B', 'C', 'D', 'E', 'A']
From what I understand, I tried to edit your code. Hopefully it helps.
import numpy as np
def get_order(new, old):
order = []
for element in new:
order.append(old.index(element))
return order
def main():
old_1 = ['A', 'B', 'C', 'D', 'E', 'F']
new = ['B', 'C', 'D', 'E', 'A']
order = get_order(new, old_1)
print(order)
old_2 = ['A', 'B', 'C', 'D', 'E', 'F']
old_2 = np.array(old_2)
order = np.array(order)
#inds = order.argsort()
#print('inds =', inds) # As a check, this gives the wrong order: [4 1 0 2 3]
new_2 = old_2[order]
print(new_2)
if __name__ == '__main__':
main()
Output
[1, 2, 3, 4, 0]
['B' 'C' 'D' 'E' 'A']
Is there method or some smart way that's easy to read to make a combination of elements in Groovy? I'm aware of Iterable#combinations or GroovyCollections#combinations but it makes Partial permutation with repetition as I understand it so far. See example.
// Groovy combinations result
def e = ['a', 'b', 'c']
def result = [e, e].combinations()
assert [['a', 'a'], ['b', 'a'], ['c', 'a'], ['a', 'b'], ['b', 'b'], ['c', 'b'], ['a','c'], ['b', 'c'], ['c', 'c']] == result
// What I'm looking for
def e = ['a', 'b', 'c']
def result = ???
assert [['a', 'b'], ['a', 'c'], ['b', 'c']] == result
Feel free to post alternate solutions. I'm still looking for better readability (it's used in script for non-developers) and performance (w/o unnecessary iterations).
I'm not so sure about the readability, but this should do the trick.
def e = ['a', 'b', 'c']
def result = [e, e].combinations().findAll { a, b ->
a < b
}
assert [['a', 'b'], ['a', 'c'], ['b', 'c']] == result
Note that if a element occur twice in the list its combinations will also occur twice. Add a '.unique()' at the end if they are unwanted
Here's a more generalized approach that allows you to specify the "r" value for your nCr combinations. It does this by storing permutations in Sets, with the Sets providing the uniqueness:
// returns combinations of the input list of the provided size, r
List combinationsOf(List list, int r) {
assert (0..<list.size()).contains(r) // validate input
def combs = [] as Set
list.eachPermutation {
combs << it.subList(0, r).sort { a, b -> a <=> b }
}
combs as List
}
// the test scenario...
def e = ['a', 'b', 'c']
def result = combinationsOf(e, 2)
assert [['a', 'b'], ['a', 'c'], ['b', 'c']] == result