Why are the keys of a dictionary going inside the items? - python

I have a problem that it seems to me that it doesn't make sense. I am defining a dictionary and using it to generate a list, with keys as the first elements of the list. But when I run it, not only the list is created, but the dictionary is modified. I need to know why this is happening and in which other way I could do this list without modifying the dictionary. A generical code example is the following:
class report:
def __init__(self):
self.dict_content= self.get_dict()
self.labels = self.get_labels()
def get_dict(self):
dict_content = dict(A1 = ['a', 'b', 'c'], A2 = ['d', 'e', 'f'])
return dict_content
def get_labels(self):
labels = []
for item in self.dict_content.items():
new_items = item[1]
new_items.insert(0, item[0])
labels.append(new_items)
return labels
Calling in the console,
r = report()
labels = r.labels
print(labels)
[['A1', 'a', 'b', 'c'], ['A2', 'd', 'e', 'f']]
dict_content = r.dict_content
print(dict_content)
{'A1': ['A1', 'a', 'b', 'c'], 'A2': ['A2', 'd', 'e', 'f']}
If I comment the line self.labels = self.get_labels() and do the last operations, I get:
r = report()
dict_content = r.dict_content
print(dict_content)
{'A1': ['a', 'b', 'c'], 'A2': ['d', 'e', 'f']}
And what I expect it to be is:
r = report()
labels = r.labels
print(labels)
[['A1', 'a', 'b', 'c'], ['A2', 'd', 'e', 'f']]
dict_content = r.dict_content
print(dict_content)
{'A1': ['a', 'b', 'c'], 'A2': ['d', 'e', 'f']}
What is happening?

for item in self.dict_content.items():
new_items = item[1]
new_items.insert(0, item[0])
labels.append(new_items)
Here, new_items, despite its name, is not a new list, but a reference to the original list contained in dict_content.
By using its insert method, you modify this list, which is reflected when looking at dict_content later.
Instead of modifying the original list, you want to create a new list. For example, by concatenation:
for item in self.dict_content.items():
new_items = [item[0]] + item[1]
labels.append(new_items)

Related

How to check if a name is in a dictionary when the values are lists of names

I have a list of names, and I am trying to loop through that list and see if a name is a value in the name_types dictionary, and if it is then I want to add the name to a results list with a list of the name types that it belongs to, however, I am not sure about how to do this. Also, I want to store None if it is not a part of any.
name_types = {'Protocol': ['a', 'b', 'c'], 'Tech': ['a', 'b', 'd']}
names = ['a', 'b', 'c', 'd']
# Goal
result[['a', ['Protocol', 'Tech']], ['b', ['Protocol', 'Tech']], ['c', ['None']], ['d', ['Tech']]]
I tried something like this, but I got too many values to unpack error:
result = []
for n in names:
list_types = []
for key, list_names in name_types:
if d in list_names:
list_types.append(key)
result.append(d, list_types)
print(result)
Your data and result don't match ('c' is a 'Protocol'). I've removed 'c' to match the desired result:
name_types = {'Protocol': ['a', 'b'], 'Tech': ['a', 'b', 'd']}
names = ['a', 'b', 'c', 'd']
result = []
for name in names:
current = [name,[]]
for k,v in name_types.items():
if name in v:
current[1].append(k)
if not current[1]:
current[1].append('None')
result.append(current)
print(result)
Output:
[['a', ['Protocol', 'Tech']], ['b', ['Protocol', 'Tech']], ['c', ['None']], ['d', ['Tech']]]
Iterate over a dict key+value with .items(), then fix the variable d => n
for n in names:
list_types = []
for key, list_names in name_types.items():
if n in list_names:
list_types.append(key)
result.append([n, list_types])
[['a', ['Protocol', 'Tech']], ['b', ['Protocol', 'Tech']], ['c', ['Protocol']], ['d', ['Tech']]]
Could do it another way, maybe nicer
result = {name: [] for name in names}
for key, list_names in name_types.items():
for name in list_names:
result[name].append(key)
print(result.items())

List of Dictionary Values

I have the dictionary as below:
tf ={1: ['a', 'b', 'c'], 2: ['d', 'x', 'y']}
I want to form the list of values as:
wrd_list = ['a', 'b', 'c', 'd', 'x', 'y']
I tried to do this by using the following code:
wrd_list = []
for k, v in tf.items():
for i in v:
word_list.append(i)
is there any efficient way to do this?
Using extend here is faster than append when you want to concatenate lists:
word_list = []
for v in tf.values():
word_list.extend(v)

Return lists of lists from recursive function

Problem
I have a hard time figuring out how to return a nested list from a recursive function. I have a nested structure, from which I want to return elements from each level.
Input
I have a structure similar to the following, where I however do not know the depth.
# Data
my_input = {'a': {'d':None, 'e':None, 'f':{'g':None}}, 'b':None, 'c':None}
Output
I need all possible levels output to a list of lists
# Desired output
[['a'], ['b'], ['c'], ['a', 'd'], ['a', 'e'], ['a', 'f'], ['a', 'f', 'g']]
What I have tried
This function does not work at all. It seems I am not able to get my head around how to return from a recursive function. Whenever I run through the function I end up either overwriting the output, or not having the correct information from the previous iteration. Any suggestions of how to write this function properly?
def output_levels(dictionary, output=None):
print(dictionary)
if not output:
output = []
if len(dictionary.keys()) == 1:
return output.append(dictionary.keys())
for key in dictionary.keys():
if not dictionary[key]:
output.append(key)
continue
output.append(output_levels(dictionary[key], output.append(key)))
return output
You could do:
my_input = {'a': {'d': None, 'e': None, 'f': {'g': None}}, 'b': None, 'c': None}
def paths(d, prefix=None):
if prefix is None:
prefix = []
for key, value in d.items():
if value is not None:
yield prefix + [key]
yield from paths(value, prefix=prefix + [key])
else:
yield prefix + [key]
print(sorted(paths(my_input), key=len))
Output
[['a'], ['b'], ['c'], ['a', 'd'], ['a', 'e'], ['a', 'f'], ['a', 'f', 'g']]
Simply we can do something like this:
dictionary = {
'a': {
'd': None,
'e': None,
'f': {
'g': None,
},
},
'b': None,
'c': None,
}
expected_output = [
['a'], ['b'], ['c'],
['a', 'd'], ['a', 'e'], ['a', 'f'],
['a', 'f', 'g'],
]
def get_levels(dictionary, parents=[]):
if not dictionary:
return []
levels = []
for key, val in dictionary.items():
cur_level = parents + [key]
levels.append(cur_level)
levels.extend(get_levels(val, cur_level))
return levels
output = get_levels(dictionary)
print(output)
assert sorted(output) == sorted(expected_output)
Slightly shorter recursive approach with yield:
my_input = {'a': {'d':None, 'e':None, 'f':{'g':None}}, 'b':None, 'c':None}
def get_paths(d, c = []):
for a, b in getattr(d, 'items', lambda :[])():
yield c+[a]
yield from get_paths(b, c+[a])
print(list(get_paths(my_input)))
Output:
[['a'], ['a', 'd'], ['a', 'e'], ['a', 'f'], ['a', 'f', 'g'], ['b'], ['c']]

Unexpected result reversing Python array

When I write this code:
f=['a','b','c',['d','e','f']]
def j(f):
p=f[:]
for i in range(len(f)):
if type(p[i]) == list:
p[i].reverse()
p.reverse()
return p
print(j(f), f)
I expect that the result would be:
[['f', 'e', 'd'], 'c', 'b', 'a'] ['a', 'b', 'c', ['d', 'e', 'f']]
But the result I see is:
[['f', 'e', 'd'], 'c', 'b', 'a'] ['a', 'b', 'c', ['f', 'e', 'd']]
Why? And how can I write a code that do what I expect?
reverse modifies the list in place, you actually want to create a new list, so you don't reverse the one you've got, something like this:
def j(f):
p=f[:]
for i in range(len(f)):
if type(p[i]) == list:
p[i] = p[i][::-1]
p.reverse()
return p

My Python module returns wrong list

I done the following Python script which should return a list of sublists.
def checklisting(inputlist, repts):
result = []
temprs = []
ic = 1;
for x in inputlist
temprs.append(x)
ic += 1
if ic == repts:
ic = 1
result.append(temprs)
return result
Example: If I called the function with the following arguments:
checklisting(['a', 'b', 'c', 'd'], 2)
it would return
[['a', 'b'], ['c', 'd']]
or if I called it like:
checklisting(['a', 'b', 'c', 'd'], 4)
it would return
[['a', 'b', 'c', 'd']]
However what it returns is a weird huge list:
>>> l.checklisting(['a','b','c','d'], 2)
[['a', 'b', 'c', 'd'], ['a', 'b', 'c', 'd'], ['a', 'b', 'c', 'd'], ['a', 'b', 'c', 'd']]
Someone please help! I need that script to compile a list with the data:
['water tax', 20, 'per month', 'electric tax', 1, 'per day']
The logic behind it is that it would separe sequences in the list the size of repts into sublists so it can be better and easier organized. I don't want arbitrary chunks of sublists as these in the other question don't specify the size of the sequence correctly.
Your logic is flawed.
Here are the bugs: You keep appending to temprs. Once repts is reached, you need to remove elements from temprs. Also, list indexes start at 0 so ic should be 0 instead of 1
Replace your def with:
def checklisting(inputlist, repts):
result = []
temprs = []
ic = 0;
for x in inputlist:
temprs.append(x)
ic += 1
if ic == repts:
ic = 0
result.append(temprs)
temprs = []
return result
Here is link to working demo of code above
def split_into_sublists(list_, size):
return list(map(list,zip(*[iter(list_)]*size)))
#[iter(list_)]*size this creates size time lists, if
#size is 3 three lists will be created.
#zip will zip the lists into tuples
#map will covert tuples to lists.
#list will convert map object to list.
print(split_into_sublists(['a', 'b', 'c', 'd'], 2))
[['a', 'b'], ['c', 'd']]
print(split_into_sublists(['a', 'b', 'c', 'd'], 4))
[['a', 'b', 'c', 'd']]
I got lost in your code. I think the more Pythonic approach is to slice the list. And I can never resist list comprehensions.
def checklisting(inputlist, repts):
return [ input_list[i:i+repts] for i in range(int(len(input_list)/repts)) ]

Categories

Resources