Reserving space for list - python

I have to make list2 which use name from list1 but number of name in list1 can vary.
foo = ['spam', 'eggs']
bar = [['spam', ['a', 'b']], ['eggs', ['c', 'd']]]
So, I reserve bar by
bar = [[None] * 2] * len(foo)
and copy names from list1 by looping
bar[i][0] = foo[i]
but the result is the name in every sublist are the same like this
bar = [['eggs', ['a', 'b']], ['eggs', ['c', 'd']]]
I try to reserve by
bar = [[None, None], [None, None]]
and no issue at all. So I think the problem come from how I reserve the list.
How can I fix this. If you don't understand my English, please ask. Thanks.

Create your second list like this:
list2 = [[None]*2 for x in range(len(list1))]
or alternativly, if for some reason you don't like to use comprehensions, you could do
list2 = []
for x in range(len(list1)):
list2.append([None,None])
The problem is that when you do something like
[listItem] * numCopies
you get a list that contains numCopies copies of the same listItem, so your sublists are all the same - when you change one you change them all.
The way that I have suggested will create unique lists that contain the same content (two copies of None). Thus changing one of these sublists will not change any others.

Python list type is for contiguous sequences, not arrays. (Python does have an array type, but list is not that.)
The example data structure you show (a sequence of pairs, with a single name and a collection of values) would be IMO better served by a mapping. Python's built-in mapping type is dict.
foo = ['spam', 'eggs']
bar = {
'spam': ['a', 'b'],
'eggs': ['c', 'd'],
}
So there is no need to reserve space in a Python list nor a Python dict. Just assign and delete items as you need, and the collection will manage its own space.
When you want to set items in the mapping bar keyed by the values you already have in the list foo, you just use a value from the list as a key in the dict:
for name in foo:
value = determine_what_is_the_value_for(name)
bar[name] = value

Related

set item at multiple indexes in a list

I am trying to find a way to use a list of indexes to set values at multiple places in a list (as is possible with numpy arrays).
I found that I can map __getitem__ and a list of indexes to return the values at those indexes:
# something like
a_list = ['a', 'b', 'c']
idxs = [0, 1]
get_map = map(a_list.__getitem__, idxs)
print(list(get_map)) # yields ['a', 'b']
However, when applying this same line of thought to __setitem__, the setting fails. This probably has something to do with pass-by-reference vs pass-by-value, which I have never fully understood no matter how many times I've read about it.
Is there a way to do this?
b_list = ['a', 'b', 'c']
idxs = [0, 1]
put_map = map(b_list.__setitem__, idx, ['YAY', 'YAY'])
print(b_list) # yields ['YAY', 'YAY', 'c']
For my use case, I only want to set one value at multiple locations. Not multiple values at multiple locations.
EDIT: I know how to use list comprehension. I am trying to mimic numpy's capability to accept a list of indexes for both getting and setting items in an array, except for lists.
The difference between the get and set case is that in the get case you are interested in the result of map itself, but in the set case you want a side effect. Thus, you never consume the map generator and the instructions are never actually executed. Once you do, b_list gets changed as expected.
>>> put_map = map(b_list.__setitem__, idxs, ['YAY', 'YAY'])
>>> b_list
['a', 'b', 'c']
>>> list(put_map)
[None, None]
>>> b_list
['YAY', 'YAY', 'c']
Having said that, the proper way for get would be a list comprehension and for set a simple for loop. That also has the advantage that you do not have to repeat the value to put in place n times.
>>> for i in idxs: b_list[i] = "YAY"
>>> [b_list[i] for i in idxs]
['YAY', 'YAY']

Dynamically append sliced list items to a dictionary in python

I have a result dictionary with pre-defined keys that should be populated based on slices of an array without explicitly accessing the dictionary keys, below is an example of my approach
my_list = ['a','b','c','d','e']
my_dict = {'first_item':'', 'middle_items':'','last_item':''}
for key in my_dict.keys():
value = my_list.pop()
my_dict.update({k:''.join(value)})
This approach obviously does not work because pop does not slice the array. And if I want to use slicing, I will have to explicitly access the dictionary variables and assign the corresponding list slices.
I have tried using the list length to slice through the list, but was unable to find a general solution, here is my other approach
for key in my_dict.keys():
value = ''.join(my_list[:-len(my_list)+1])
del my_list[0]
my_dict.update({k:v})
How can I slice a list in a general way such that it splits into a first item, last item, and middle items? below is how the updated dictionary should look like
my_dict = {'first_item':'a', 'middle_items':'b c d','last_item':'e'}
Edit: if I use [0],[1:-1], and [-1] slices then that means that I will have to access each dictionary key individually and update it rather than loop over it (which is the desired approach)
If you are using python 3 then you should try this idiom:
my_list = ['a','b','c','d','e']
first_item, *middle_items, last_item = my_list
my_dict = dict(
first_item=first_item,
middle_items=' '.join(middle_items),
last_item=last_item
)
print(my_dict)
# {'last_item': 'e', 'middle_items': 'b c d', 'first_item': 'a'}
To get a slice of my_list, use the slice notation.
my_list = ['a', 'b', 'c', 'd', 'e']
my_dict = {
'first_item': my_list[0],
'middle_items': ' '.join(my_list[1:-1]),
'last_item': my_list[-1]
}
Output
{'first_item': 'a',
'middle_items': 'b c d',
'last_item': 'e'}

How to arrange the output of set based on predefined list

list1=['f','l','a','m','e','s'] #This is the predefined list
list2=['e','e','f','a','s','a'] #This is the list with repitition
x=list(set(list2)) # I want to remove duplicates
print(x)
Here I want the variable x to retain the order which list1 has. For example, if at one instance set(list2) produces the output as ['e','f','a','s'], I want it to produce ['f','a','e','s'] (Just by following the order of list1).
Can anyone help me with this?
Construct a dictionary that maps characters to their position in list1. Use its get method as the sort-key.
>>> dict1 = dict(zip(list1, range(len(list1))))
>>> sorted(set(list2), key=dict1.get)
['f', 'a', 'e', 's']
This is one way using dictionary:
list1=['f','l','a','m','e','s'] #This is the predefined list
list2=['e','e','f','a','s','a'] #This is the list with repitition
x=list(set(list2)) # I want to remove duplicates
d = {key:value for value, key in enumerate(list1)}
x.sort(key=d.get)
print(x)
# ['f', 'a', 'e', 's']
Method index from the list class can do the job:
sorted(set(list2), key=list1.index)
What is best usually depends on actual use. With this problem it is important to know the expected sizes of the lists to choose the most efficient approach. If we are keeping much of the dictionary the following query works well and has the additional benefit that it is easy to read.
set2 = set(list2)
x = [i for i in list1 if i in set2]
It would also work without turning list2 into a set first. However, this would run much slower with a large list2.

Remove element in list using list comprehension - Python

I have a list like this:
['A','B','C']
What I need is to remove one element based on the input I got in the function. For example, if I decide to remove A it should return:
['B','C']
I tried with no success
list = ['A','B','C']
[var for var in list if list[var] != 'A']
How can I do it?
Thanks
Simple lst.remove('A') will work:
>>> lst = ['A','B','C']
>>> lst.remove('A')
['B', 'C']
However, one call to .remove only removes the first occurrence of 'A' in a list. To remove all 'A' values you can use a loop:
for x in range(lst.count('A')):
lst.remove('A')
If you insist on using list comprehension you can use
>>> [x for x in lst if x != 'A']
['B', 'C']
The above will remove all elements equal to 'A'.
The improvement to your code (which is almost correct) would be:
list = ['A','B','C']
[var for var in list if var != 'A']
However, #frostnational's approach is better for single values.
If you are going to have a list of values to disallow, you can do that as:
list = ['A','B','C', 'D']
not_allowed = ['A', 'B']
[var for var in list if var not in not_allowed]
If you not sure whether the element exists or not, you might want to check before you delete:
if 'A' in lst:
lst.remove('A')
Find this simplified code:
list1 = [12,24,35,24,88,120,155]
while 24 in list1:
list1.remove(24)
print(list1)
Best Luck!
originalList=['A','B','C']
print([val for val in originalList if val!='A'])
This prints
['B', 'C']
You can just use the remove method of list. Just do list.remove('A') and it will be removed.
If you have the index of the item to be removed, use the pop method. list.pop(0).
You were really close:
list = ['A','B','C']
[var for var in list if list[list.index(var)] != 'A']
You tried to refer to a list item using a syntax that calls for an index value.

Python - List of Lists Slicing Behavior

When I define a list and try to change a single item like this:
list_of_lists = [['a', 'a', 'a'], ['a', 'a', 'a'], ['a', 'a', 'a']]
list_of_lists[1][1] = 'b'
for row in list_of_lists:
print row
It works as intended. But when I try to use list comprehension to create the list:
row = ['a' for range in xrange(3)]
list_of_lists = [row for range in xrange(3)]
list_of_lists[1][1] = 'b'
for row in list_of_lists:
print row
It results in an entire column of items in the list being changed. Why is this? How can I achieve the desired effect with list comprehension?
Think about if you do this:
>>> row = ['a' for range in xrange(3)]
>>> row2 = row
>>> row2[0] = 'b'
>>> row
['b', 'a', 'a']
This happens because row and row2 are two different names for the same list (you have row is row2) - your example with nested lists only obscures this a little.
To make them different lists, you can cause it to re-run the list-creation code each time instead of doing a variable assignment:
list_of_lists = [['a' for range in xrange(3)] for _ in xrange(3)]
or, create a new list each time by using a slice of the full old list:
list_of_lists = [row[:] for range in xrange(3)]
Although this isn't guaranteed to work in general for all sequences - it just happens that list slicing makes a new list for the slice. This doesn't happen for, eg, numpy arrays - a slice in those is a view of part of the array rather than a copy. If you need to work more generally than just lists, use the copy module:
from copy import copy
list_of_lists = [copy(row) for range in xrange(3)]
Also, note that range isn't the best name for a variable, since it shadows the builtin - for a throwaway like this, _ is reasonably common.
This happens because most objects in python (exept for strings and numbers) get passed reference (not exactly by reference, but here you have a better explanation) so when you try to do it in the "list comprehensive" way, yo get a list of 3 references to the same list (the one you called "row"). So when you change the value of one row you see that change in all of them)
So what you have to do is to change your "matrix" creation like this:
list_of_lists = [list(row) for range in xrange(3)]
Here you have some ideas on how to correctly get a copy of a list. Depending on what you are trying to do, you may use one or another...
Hope it helps!
Copy the list instead of just the reference.
list_of_lists = [row[:] for range in xrange(3)]

Categories

Resources