The dictionary's methods .viewvalues() and .viewkeys() allow to create the list variables that will be linked and dynamically updated on every dictionary modification such as:
diction={'one':1,'two':2,'three':3}
dict_values=dictVar.viewvalues()
dict_keys=dictVar.viewkeys()
I wonder if a similar functionality could be achieved with lists. So if there are two "source" list variables and a third list is a result of sums of twos:
a=[1,2,3]
b=[4,5,6]
sum=a+b
Now what i want is a list variable sum to get updated if/when list variable a or list variable b is modified. How to achieve that?
I'd define a function to do it and then call that whenever you need the list.
a=[1,2,3]
b=[4,5,6]
def sum(a, b):
return a + b
Then, in an interpreter:
>>> sum(a, b)
[1, 2, 3, 4, 5, 6]
>>> a.append(5)
>>> sum(a, b)
[1, 2, 3, 5, 4, 5, 6]
If it's not necessary that it be a flat list, you can easily do what you'd want.
>>> a = [1, 2, 3]
>>> b = [4, 5, 6]
>>> sum = [a, b]
>>> print(sum)
[[1, 2, 3], [4, 5, 6]]
>>> a.append(8)
>>> print(sum)
[[1, 2, 3, 8], [4, 5, 6]]
That said, I'd recommend against defining a variable named sum as it's a built-in Python function.
You could do it the other way around, using numpy arrays.
>>> import numpy as np
>>> ab = np.array([1,2,3,4,5,6])
>>> a = ab[:3]
>>> b = ab[3:]
>>> a, b
(array([1, 2, 3]), array([4, 5, 6]))
>>> a[1] = 9
>>> ab
array([1, 9, 3, 4, 5, 6])
>>> ab[0] = 7
>>> a
array([7, 9, 3])
Here, a and b are "views" on the array ab, and modifying one will also modify the other.
Starting with a and b, just create a numpy array from a+b and redefine a and b accordingly:
>>> a, b = [1,2,3], [4,5,6]
>>> ab = np.array(a+b)
>>> a, b = ab[:3], ab[3:]
You will have to right a custom data structure to do this. Here is something in the right direction...
class LinkedArrays(object):
def __init__(self, sourceArray1, sourceArray2, combineFunction):
self.sa1, self.sa2 = sourceArray1, sourceArray2
self.__combineFunction = combineFunction
self.__update()
def updateSourceArray1(self, index, value):
self.sa1[index] = value
self.__update()
def updateSourceArray2(self, index, value):
self.sa2[index] = value
self.__update()
def __update(self):
self.combinedArray = [self.__combineFunction(self.sa1[i], self.sa2[i]) for i in range(len(self.sa1))]
def __getitem__(self, item):
return self.combinedArray[item]
summedArrays = LinkedArrays([1, 2, 3], [4, 5, 6], lambda x, y: x+y)
print summedArrays[0] # print 5
summedArrays.updateSourceArray1(0, 6)
print summedArrays[0] # print 10
Related
Is there a way I can use something like this:
a, b, c = [1, 2, 3, 4, 5]
In order to get the values:
a = 1
b = [2, 3]
c = [4, 5]
To break up existing data as needed:
>>> data = [1,2,3,4,5]
>>> a,b,c = data[0],data[1:3],data[3:]
>>> a
1
>>> b
[2, 3]
>>> c
[4, 5]
Given multiple lists like the ones shown:
a = [1, 2, 3]
b = [5, 6, 7, 8]
c = [9, 0, 1]
d = [2, 3, 4, 5, 6, 7]
...
I want to be able to combine them to take as many elements from the first list as I can before starting to take elements from the second list, so the result would be:
result = [1, 2, 3, 8, 6, 7]
Is there a particularly nice way to write this? I can't think of a really simple one without a for loop. Maybe a list comprehension with a clever zip.
Simple slicing and concatenation:
a + b[len(a):]
Or with more lists:
res = []
for lst in (a, b, c, d):
res += lst[len(res):]
# [1, 2, 3, 8, 6, 7]
With itertools.zip_longest() for Python 3, works on any number of input lists:
>>> from itertools import zip_longest
>>> [next(x for x in t if x is not None) for t in zip_longest(a,b,c,d)]
[1, 2, 3, 8, 6, 7]
The default fill value is None so take the first none None element in each tuple created with the zip_longest call (you can change the defaults and criteria if None is a valid data value)
With functools.reduce:
from functools import reduce
print(list(reduce(lambda a, b: a + b[len(a):], [a, b, c, d])))
This outputs:
[1, 2, 3, 8, 6, 7]
I have several lists, let's say they look like:
a = [0, 1, 2]
b = [3, 4, 5, 6]
And I want to have a list or similarly iterable data structure which stores all the elements in both a and b:
c = [0, 1, 2, 3, 4, 5, 6]
changing any of these elements changes the corresponding element in the original list.
c[0] = 10
a
[10, 1, 2]
Most resources I've found are concerned with doing the opposite - creating list copies with distinct IDs for the elements. Is there a simple solution?
EDIT - Ilja Everilä suggested itertools.chain which works nicely. Although it doesn't support mutation, I can use it to build new lists which fits my use case.
Perhaps something like this:
class IndirectList():
def __init__(self, *args):
self.array = list()
for subarray in range(len(args)):
for element in range(len(args[subarray])):
self.array.append((args[subarray], element))
def __len__(self):
return len(self.array)
def __getitem__(self, key):
if key not in range(len(self.array)):
raise IndexError
return (self.array[key][0])[self.array[key][1]]
def __setitem__(self, key, value):
if key not in range(len(self.array)):
raise IndexError
(self.array[key][0])[self.array[key][1]] = value
USAGE
>>> a = [0, 1, 2]
>>> b = [3, 4, 5, 6]
>>> c = IndirectList(a, b)
>>> c
<__main__.IndirectList object at 0x10187d9b0>
>>> list(c)
[0, 1, 2, 3, 4, 5, 6]
>>> c[4]
4
>>> c[4] = 13
>>> list(c)
[0, 1, 2, 3, 13, 5, 6]
>>> a
[0, 1, 2]
>>> b
[3, 13, 5, 6]
>>> a[1] = -42
>>> a
[0, -42, 2]
>>> b
[3, 13, 5, 6]
>>> list(c)
[0, -42, 2, 3, 13, 5, 6]
This class needs extending and optimizing but the basic idea is there.
I have the following lists
a=[1,2,3]
b=[4,5,6]
c=[a,b]
i need to combine both list a and b.
result should be like [1,2,3,4,5,6]
i tried with list comprehension
[x for x in i for i in c]
output
[3, 3, 4, 4, 5, 5]
How can i get the result as [1,2,3,4,5,6] using list comprehension.
You can just do:
a + b
If you must use list comprehension:
In [10]: a = [1, 2, 3]
In [11]: b = [4, 5, 6]
In [12]: c = [a, b]
In [13]: [j for i in c for j in i]
Out[13]: [1, 2, 3, 4, 5, 6]
Use itertools.chain.
import itertools
a=[1,2,3]
b=[4,5,6]
c = list(itertools.chain(a, b))
You are concatenating, use + to do so:
c = a + b
If you are concatenating an arbitrary number of lists, use itertools.chain.from_iterable():
from itertools import chain
list_of_lists = [a, b]
c = list(chain.from_iterable(list_of_lists))
Note that if all you need to do is iterate over the concatenation result, you can leave of the list() call altogether.
Do not use sum() for this; that leads to quadratic behaviour as intermediate results are built for every element summed, which takes a full loop.
You can do it with + operation
a = [1, 2, 3]
b = [3, 4, 5]
c = a + b # Equal [1, 2, 3, 3, 4, 5]
Here are 3 different ways you can do it:
>>> a=[1,2,3]
>>> b=[4,5,6]
>>> c=a+b
>>> c
[1, 2, 3, 4, 5, 6]
>>> c=[item for l in [a, b] for item in l]
>>> c
[1, 2, 3, 4, 5, 6]
>>> import itertools
>>> list(itertools.chain(*[a, b]))
[1, 2, 3, 4, 5, 6]
Suppose I have a list x = [1,2,3] and I want to output every other value than the indexed one, is there a list operation I can use?, ie: x[0]=> [2,3], x[1] => [1,3], x[2] =>[1,2] ?
You could use this:
def exclude(l, e):
return [v for i, v in enumerate(l) if i != e]
>>> exclude(range(10), 3)
[0, 1, 2, 4, 5, 6, 7, 8, 9]
You could do it with a slice, but I'd be tempted to try:
a = [1, 2, 3]
b = a[:]
del b[1]
edit
The above does "technically" use a slice operation, which happens to be on list objects in effect a shallow-copy.
What's more flexible and shouldn't have any downsides is to use:
a = [1, 2, 3]
b = list(a)
del b[1]
The list builtin works on any iterable (while the slice operation [:] works on lists or those that are indexable) so that you could even extend it to constructs such as:
>>> a = '123'
>>> b = list(a)
>>> del b[0]
>>> ''.join(b)
'23'
You could use x[:i] + x[i+1:]:
In [8]: x = [1, 2, 3]
In [9]: i = 0
In [10]: x[:i] + x[i+1:]
Out[10]: [2, 3]
Depending on the context, x.pop(i) might also be useful. It modifies the list in place by removing and returning the i-th element. If you don't need the element, del x[i] is also an option.
>>> x = [1, 2, 3]
>>> x[:1] + x[2:]
[1, 3]
my_list = [1, 2, 3]
my_list.remove(my_list[_index_]) #_index_ is the index you want to remove
Such that: my_list.remove(my_list[0]) would yield [2, 3],
my_list.remove(my_list[1]) would yield [0, 3], and
my_list.remove(my_list[2]) would yield [1, 2].
So you want every value except the indexed value:
Where i is the index:
>>> list = [1,2,3,4,5,6,7,8]
>>> [x for x in list if not x == list[i]]
This will give you a list with no instances of the i't element, so e.g.:
>>> i = 2
>>> list = [1,2,3,4,5,6,7,1,2,3,4,5,6,7]
>>> [x for x in list if not x == list[i]]
[1, 2, 4, 5, 6, 7, 1, 2, 4, 5, 6, 7]
note how 3 is not in that list at all.
Every other is
x[::2], start at 0
x[1::2], start at 1