Use list of strings elements as arrays - python

I have a list of strings:
list1 = ['array1', 'array2', 'array3']
whose elements I would like to use as names of other lists, like (as conceptual example):
list1[0] = [1, 2, 3]
I know this assignation does not make any sense, but it is only to show what I need.
I have looked for this a lot but didn't find a handy example. If I understood properly, this is not the right way to do it, and better is to use dictionaries. But, I never used dictionaries yet, so I would need some examples.

aDict = { name: 42 for name in list1 }
This gives you:
{'array3': 42, 'array2': 42, 'array1': 42}
If you wanted it ordered:
from collections import OrderedDict
aDict = OrderedDict((name, 42) for name in list1)

Use a dictionary:
list1 = {'array1': [0, 1, 2], 'array2': [0, 3], 'array3': [1]}
and then access it like this:
list1['array1'] # output is [0, 1, 2]
To dynamically populate your dictionary:
list1 = {'array1': []}
list1['array1'].append(1)

You can do What you want with exec like this :
list1 = ['array1', 'array2', 'array3']
x=list1[1]
exec("%s = %d" % (x,2))
print array2
so result is :
2
But never use exec when you can use something much safer like dictionary, it can be dangerous !

Related

How to change a value inside a list which is a value for a key in a dictionary?

I try to change one value inside the list but all values change for all keys.
vertex_list = ['a','b']
distance_dict = dict.fromkeys(vertex_list, [10, 'None'])
distance_dict['a'][0] = 1
print(distance_dict)
output:
{'a': [1, 'None'], 'b': [1, 'None']}
when I built the dictionary with traditional { } it works fine. I guess the problem is for the list inside dict.fromkeys, which creates one list for all dictionary keys. is there a solution to fix it. without using ''for'' and { } to build the dictionary?
Quoting from the official documentation,
fromkeys() is a class method that returns a new dictionary. value
defaults to None. All of the values refer to just a single instance,
so it generally doesn’t make sense for value to be a mutable object
such as an empty list. To get distinct values, use a dict
comprehension instead.
Means that dict.fromkeys is useful if the second argument is a singleton instance(like None). So the solution is to use the dict comprehension.
distance_dict = {vertex: [10, None] for vertex in vertex_list}
If you print the id of distance_dict 's value created by dict.fromkeys:
vertex_list = ['a','b']
distance_dict = dict.fromkeys(vertex_list, [10, 'None'])
print(id(distance_dict['a']), id(distance_dict['b']))
print(id(distance_dict['a']) == id(distance_dict['b']))
Output:
2384426495040 2384426495040
True
distance_dict['a'] and distance_dict['b'] are actually the same list object, occupying the same memory space.
If you use the dict comprehension:
distance_dict = {vertex: [10, None] for vertex in vertex_list}
print(id(distance_dict['a']) == id(distance_dict['b']))
Output:
False
They are different list objects with the same elements.
You can solve with:
vertex_list = ['a','b']
distance_dict = {x: [10, 'None'] for x in vertex_list}
distance_dict['a'][0] = 1
print(distance_dict)
Output:
{'a': [1, 'None'], 'b': [10, 'None']}

What does AttributeError: 'tuple' object has no attribute 'append' means or fixed? [duplicate]

I want to do something like this:
myList = [10, 20, 30]
yourList = myList.append(40)
Unfortunately, list append does not return the modified list.
So, how can I allow append to return the new list?
See also: Why do these list operations (methods) return None, rather than the resulting list?
Don't use append but concatenation instead:
yourList = myList + [40]
This returns a new list; myList will not be affected. If you need to have myList affected as well either use .append() anyway, then assign yourList separately from (a copy of) myList.
In python 3 you may create new list by unpacking old one and adding new element:
a = [1,2,3]
b = [*a,4] # b = [1,2,3,4]
when you do:
myList + [40]
You actually have 3 lists.
list.append is a built-in and therefore cannot be changed. But if you're willing to use something other than append, you could try +:
In [106]: myList = [10,20,30]
In [107]: yourList = myList + [40]
In [108]: print myList
[10, 20, 30]
In [109]: print yourList
[10, 20, 30, 40]
Of course, the downside to this is that a new list is created which takes a lot more time than append
Hope this helps
Try using itertools.chain(myList, [40]). That will return a generator as a sequence, rather than allocating a new list. Essentially, that returns all of the elements from the first iterable until it is exhausted, then proceeds to the next iterable, until all of the iterables are exhausted.
Unfortunately, none of the answers here solve exactly what was asked. Here is a simple approach:
lst = [1, 2, 3]
lst.append(4) or lst # the returned value here would be the OP's `yourList`
# [1, 2, 3, 4]
One may ask the real need of doing this, like when someone needs to improve RAM usage, do micro-benchmarks etc. that are, usually, useless. However, sometimes someone is really "asking what was asked" (I don't know if this is the case here) and the reality is more diverse than we can know of. So here is a (contrived because out-of-a-context) usage...
Instead of doing this:
dic = {"a": [1], "b": [2], "c": [3]}
key, val = "d", 4 # <- example
if key in dic:
dic[key].append(val)
else:
dic[key] = [val]
dic
# {'a': [1], 'b': [2], 'c': [3], 'd': [4]}
key, val = "b", 5 # <- example
if key in dic:
dic[key].append(val)
else:
dic[key] = [val]
dic
# {'a': [1], 'b': [2, 5], 'c': [3], 'd': [4]}
One can use the OR expression above in any place an expression is needed (instead of a statement):
key, val = "d", 4 # <- example
dic[key] = dic[key].append(val) or dic[key] if key in dic else [val]
# {'a': [1], 'b': [2], 'c': [3], 'd': [4]}
key, val = "b", 5 # <- example
dic[key] = dic[key].append(val) or dic[key] if key in dic else [val]
# {'a': [1], 'b': [2, 5], 'c': [3], 'd': [4]}
Or, equivalently, when there are no falsy values in the lists, one can try dic.get(key, <default value>) in some better way.
You can subclass the built-in list type and redefine the 'append' method. Or even better, create a new one which will do what you want it to do. Below is the code for a redefined 'append' method.
#!/usr/bin/env python
class MyList(list):
def append(self, element):
return MyList(self + [element])
def main():
l = MyList()
l1 = l.append(1)
l2 = l1.append(2)
l3 = l2.append(3)
print "Original list: %s, type %s" % (l, l.__class__.__name__)
print "List 1: %s, type %s" % (l1, l1.__class__.__name__)
print "List 2: %s, type %s" % (l2, l2.__class__.__name__)
print "List 3: %s, type %s" % (l3, l3.__class__.__name__)
if __name__ == '__main__':
main()
Hope that helps.
Just to expand on Storstamp's answer
You only need to do
myList.append(40)
It will append it to the original list,now you can return the variable containing the original list.
If you are working with very large lists this is the way to go.
You only need to do
myList.append(40)
It will append it to the original list, not return a new list.

Append returning None [duplicate]

I want to do something like this:
myList = [10, 20, 30]
yourList = myList.append(40)
Unfortunately, list append does not return the modified list.
So, how can I allow append to return the new list?
See also: Why do these list operations (methods) return None, rather than the resulting list?
Don't use append but concatenation instead:
yourList = myList + [40]
This returns a new list; myList will not be affected. If you need to have myList affected as well either use .append() anyway, then assign yourList separately from (a copy of) myList.
In python 3 you may create new list by unpacking old one and adding new element:
a = [1,2,3]
b = [*a,4] # b = [1,2,3,4]
when you do:
myList + [40]
You actually have 3 lists.
list.append is a built-in and therefore cannot be changed. But if you're willing to use something other than append, you could try +:
In [106]: myList = [10,20,30]
In [107]: yourList = myList + [40]
In [108]: print myList
[10, 20, 30]
In [109]: print yourList
[10, 20, 30, 40]
Of course, the downside to this is that a new list is created which takes a lot more time than append
Hope this helps
Try using itertools.chain(myList, [40]). That will return a generator as a sequence, rather than allocating a new list. Essentially, that returns all of the elements from the first iterable until it is exhausted, then proceeds to the next iterable, until all of the iterables are exhausted.
Unfortunately, none of the answers here solve exactly what was asked. Here is a simple approach:
lst = [1, 2, 3]
lst.append(4) or lst # the returned value here would be the OP's `yourList`
# [1, 2, 3, 4]
One may ask the real need of doing this, like when someone needs to improve RAM usage, do micro-benchmarks etc. that are, usually, useless. However, sometimes someone is really "asking what was asked" (I don't know if this is the case here) and the reality is more diverse than we can know of. So here is a (contrived because out-of-a-context) usage...
Instead of doing this:
dic = {"a": [1], "b": [2], "c": [3]}
key, val = "d", 4 # <- example
if key in dic:
dic[key].append(val)
else:
dic[key] = [val]
dic
# {'a': [1], 'b': [2], 'c': [3], 'd': [4]}
key, val = "b", 5 # <- example
if key in dic:
dic[key].append(val)
else:
dic[key] = [val]
dic
# {'a': [1], 'b': [2, 5], 'c': [3], 'd': [4]}
One can use the OR expression above in any place an expression is needed (instead of a statement):
key, val = "d", 4 # <- example
dic[key] = dic[key].append(val) or dic[key] if key in dic else [val]
# {'a': [1], 'b': [2], 'c': [3], 'd': [4]}
key, val = "b", 5 # <- example
dic[key] = dic[key].append(val) or dic[key] if key in dic else [val]
# {'a': [1], 'b': [2, 5], 'c': [3], 'd': [4]}
Or, equivalently, when there are no falsy values in the lists, one can try dic.get(key, <default value>) in some better way.
You can subclass the built-in list type and redefine the 'append' method. Or even better, create a new one which will do what you want it to do. Below is the code for a redefined 'append' method.
#!/usr/bin/env python
class MyList(list):
def append(self, element):
return MyList(self + [element])
def main():
l = MyList()
l1 = l.append(1)
l2 = l1.append(2)
l3 = l2.append(3)
print "Original list: %s, type %s" % (l, l.__class__.__name__)
print "List 1: %s, type %s" % (l1, l1.__class__.__name__)
print "List 2: %s, type %s" % (l2, l2.__class__.__name__)
print "List 3: %s, type %s" % (l3, l3.__class__.__name__)
if __name__ == '__main__':
main()
Hope that helps.
Just to expand on Storstamp's answer
You only need to do
myList.append(40)
It will append it to the original list,now you can return the variable containing the original list.
If you are working with very large lists this is the way to go.
You only need to do
myList.append(40)
It will append it to the original list, not return a new list.

What's the best way to add two elements of an object to a list without repeating them?

Performance, elegancy and readability are the requirements for "the best way"
I have the array of dictionaries:
items = [
{'id1' : 1, 'id2' : 2, 'other' : 'xxx'},
{'id1' : 1, 'id2' : 3, 'other' : 'yyy'},
{'id1' : 2, 'id2' : 4, 'other' : 'zzz'}
]
The result should be: ids = [1,2,3,4] (list of id1 and id2)
Edit:
Something like this:
ids = []
for item in items:
if item.id1 not in ids:
ids.append(item.id1)
if item.id2 not in ids:
ids.append(item.id2)
>>> set(x for y in items for x in y.values())
set([1, 2, 3, 4])
Update for updated question
>>> set(v for y in items for (k,v) in y.items() if k.startswith('id'))
set([1, 2, 3, 4])
This could be done pretty easily by using itertools.chain.from_iterable() to flatten a nested generator expression producing the values of the ids - we presume that all keys are going to be strings, and that starting with "id" specifies an id. We then make a set of those values to remove duplicates:
from itertools import chain
set(chain.from_iterable((value for name, value in item.items()
if name.startswith("id"))
for item in items))
If you really want a list, then you could create one from the set, but in most cases, the set should be fine as-is. Note that the set has no order, so if you want an order you will need to use sorted(), for example.
itertools.chain.from_iterable() is the most efficient and readable way to flatten an iterable.
Your specification isn't clear when it comes to what an id is. If you have a set of keys which define an id, then something like this might be more appropriate as the if clause of the inner generator expression:
if name in {"id1", "id2"}

In python is there something like updated that is to update what sorted is to sort?

In python if I do the following:
>>> list = [ 3, 2, 1]
>>> sorted_list = k.sort()
Then sorted_list is None and list is sorted:
>>> sorted_list = k.sort()
>>> print list, sorted_list
[1, 2, 3] None
However, if I do the following:
>>> list = [ 3, 2, 1]
>>> sorted_list = sorted(list)
Then list remains unsorted and sorted_list contains a copy of the sorted list:
>>> print list, sorted_list
[3, 2, 1] [1, 2, 3]
I am wondering if there is an equivalent for the update function for dictionaries.
That way I could do something like this:
def foo(a, b, extra={}):
bar = { 'first': a, 'second': b }
special_function(**updated(bar, extra))
normal_function(**bar)
rather than having to do something like this:
def foo(a, b, extra={}):
bar = { 'first': a, 'second': b }
special_bar = bar.copy()
special_bar.update(extra) # [1]
special_function(**special_bar)
normal_function(**bar)
[1] Yes I realize I could simply replace these two lines with extra.update(bar) but let's assume I want to retain extra as is for later on in the function.
I realize I could implement this myself thusly:
def updated(old_dict, extra={}):
new_dict = old_dict.copy()
new_dict.update(extra)
return new_dict
Or the following highly unreadable in-place statement:
special_function(**(dict(bar.items()+extra.items())))
But I was hoping there was something built in that I could already use.
You can simply use the built-in dict():
updated_dict = dict(old_dict, **extra_dict)
If you need non-string keys, you can use a function like that: (It is not as ugly as your "in-place" expression + it works for any number of dictionaries)
from itertools import chain # ← credits go to Niklas B.
def updated(*dicts):
return dict(chain(*map(dict.items, dicts)))
updated({42: 'the answer'}, {1337: 'elite'}) # {42: 'the answer', 1337: 'elite'}
Otherwise Sven’s suggestion is just fine.
Edit: If you are using Python 2.7 or later, you can also use a dictionary comprehension, as Sven suggested in the comments:
def updated(*dicts):
return {k: v for d in dicts for k, v in d.items()}
I don't really see what's wrong in using two lines, like you do:
new_bar = bar.copy()
new_bar.update(extra)
It's clean and readable.
>>> d = {1:2, 3:4}
>>> e = {3:9, 5:25}
>>> f = d.copy()
>>> f.update(e)
>>> d
{1: 2, 3: 4}
>>> f
{1: 2, 3: 9, 5: 25}
>>> e
{3: 9, 5: 25}
In three words: Zen of Python.
To be more clear: My point is that I wouldn't replace those two lines with an updated() function that's not coming from the standard library.
If I was to stumble in a line of code like:
new_bar = updated(bar, extra)
I'd have to track that function down to see what it does. I couldn't trust that it doesn't something strange.
The OP also compared that with sorted(), but sorted() has it's reason to exist, it acts on everything that's iterable and does that with the amazing timsort. Instead what should be the behaviour of an hypothetical updated()? Should that maybe be a dict class method? It's really not clear IMHO.
Said so one could choose the OP two lines, or Sven's solution, or a dict comprehension/generator-expression, I think it's really just a matter of taste.

Categories