Repeat a list within a list X number of times - python

I'm working on a project and I need to repeat a list within a list a certain number of times. Obviously, L.append(L) just adds the elements again without creating separate lists. I'm just stumped on how to make the lists separate within the big list.
In short form, this is what I have:
L = [1,2,3,4,5]
If I wanted to to repeat it, say, 3 times so I'd have:
L = [[1,2,3,4,5],[1,2,3,4,5],[1,2,3,4,5]]
How do I achieve this? I'm looking for lists within the big list.

No need for any functions:
>>> L = [1,2,3,4,5]
>>> [L]*3
[[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]
However, you should note that if you change one value in any of the lists, all the others will change because they reference the same object.
>>> mylist = [L]*3
>>> mylist[0][0] = 6
>>> print mylist
[[6, 2, 3, 4, 5], [6, 2, 3, 4, 5], [6, 2, 3, 4, 5]]
>>> print L
[6, 2, 3, 4, 5]
To avoid this:
>>> L = [1,2,3,4,5]
>>> mylist = [L[:] for _ in range(3)]
>>> mylist[0][0] = 6
>>> print L
[1, 2, 3, 4, 5]
>>> print mylist
[[6, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]
Notice how L didn't change, and only the first list in mylist changed.
Thanks everyone in the comments for helping :).

Related

Relative size in list python

I have a list of integers. Each number can appear several times, the list is unordered.
I want to get the list of relative sizes. Meaning, if for example the original list is [2, 5, 7, 7, 3, 10] then the desired output is [0, 2, 3, 3, 1, 4]
Because 2 is the zero'th smallest number in the original list, 3 is one'th, etc.
Any clear easy way to do this?
Try a list comprehension with dictionary and also use set for getting unique values, like below:
>>> lst = [2, 5, 7, 7, 3, 10]
>>> newl = dict(zip(range(len(set(lst))), sorted(set(lst))))
>>> [newl[i] for i in lst]
[0, 2, 3, 3, 1, 4]
>>>
Or use index:
>>> lst = [2, 5, 7, 7, 3, 10]
>>> newl = sorted(set(lst))
>>> [newl.index(i) for i in lst]
[0, 2, 3, 3, 1, 4]
>>>

Subtract previous list from current list in a list of lists loop

I have a list of dataframes with data duplicating in every next dataframe within list which I need to subtract between themselves
the_list[0] = [1, 2, 3]
the_list[1] = [1, 2, 3, 4, 5, 6, 7]
There are also df headers. Dataframes are only different in number of rows.
Wanted solution:
the_list[0] = [1, 2, 3]
the_list[1] = [4, 5, 6, 7]
Due to the fact that my list of lists, the_list, contains several dataframes, I have to work backward and go from the last df to first with first remaining intact.
My current code (estwin is the_list):
estwin = [df1, df2, df3, df4]
output=([])
estwin.reverse()
for i in range(len(estwin) -1):
difference = Diff(estwin[i], estwin[i+1])
output.append(difference)
return(output)
def Diff(li_bigger, li_smaller):
c = [x for x in li_bigger if x not in li_smaller]
return (c)
Currently, the result is an empty list. I need an updated the_list that contains only the differences (no duplicate values between lists).
You should not need to go backward for this problem, it is easier to keep track of what you have already seen going forward.
Keep a set that gets updated with new items as you traverse through each list, and use it to filter out the items that should be present in the output.
list1 = [1,2,3]
list2 = [1,2,3,4,5,6,7]
estwin = [list1, list2]
lookup = set() #to check which items/numbers have already been seen.
output = []
for lst in estwin:
updated_lst = [i for i in lst if i not in lookup] #only new items present
lookup.update(updated_lst)
output.append(updated_lst)
print(output) #[[1, 2, 3], [4, 5, 6, 7]]
Your code is not runnable, but if I guess what you meant to write, it works, except that you have one bug in your algorithm:
the_list = [
[1, 2, 3],
[1, 2, 3, 4, 5, 6, 7],
[1, 2, 3, 4, 5, 6, 7, 8, 9]
]
def process(lists):
output = []
lists.reverse()
for i in range(len(lists)-1):
difference = diff(lists[i], lists[i+1])
output.append(difference)
# BUGFIX: Always add first list (now last becuase of reverse)
output.append(lists[-1])
output.reverse()
return output
def diff(li_bigger, li_smaller):
return [x for x in li_bigger if x not in li_smaller]
print(the_list)
print(process(the_list))
Output:
[[1, 2, 3], [1, 2, 3, 4, 5, 6, 7], [1, 2, 3, 4, 5, 6, 7, 8, 9]]
[[1, 2, 3], [4, 5, 6, 7], [8, 9]]
One-liner:
from itertools import chain
l = [[1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5]]
new_l = [sorted(list(set(v).difference(chain.from_iterable(l[:num]))))
for num, v in enumerate(l)]
print(new_l)
# [[1, 2], [3], [4], [5]]

Python list: exchange every n-th value with the (n+1)th

What is the best way to do this:
>>> replace2([1, 2, 3, 4, 5, 6])
[2, 1, 4, 3, 6, 5]
def replace2inplace(lst):
lst[1::2], lst[::2] = lst[::2], lst[1::2]
This uses slice assignment and slice step sizes to swap every pair in the list around, in-place:
>>> somelst = [1, 2, 3, 4, 5, 6]
>>> replace2inplace(somelst)
>>> somelst
[2, 1, 4, 3, 6, 5]
Otherwise you could use some itertools tricks:
from itertools import izip, chain
def replace2copy(lst):
lst1, lst2 = tee(iter(lst), 2)
return list(chain.from_iterable(izip(lst[1::2], lst[::2])))
which gives:
>>> replace2([1, 2, 3, 4, 5, 6])
[2, 1, 4, 3, 6, 5]
with the list() call optional; if you only need to loop over the result the generator is enough:
from itertools import izip, chain, islice, tee
def replace2gen(lst):
lst1, lst2 = tee(iter(lst))
return chain.from_iterable(izip(islice(lst1, 1, None, 2), islice(lst2, None, None, 2)))
for i in replace2gen([1, 2, 3, 4, 5, 6]):
print i
where replace2gen() can take arbitrary iterators too.
Out-of-place version:
def replace2(lst):
return [x for pair in zip(lst[1::2], lst[::2]) for x in pair]
My choice:
x = range(1,7)
res = [e for e in itertools.chain(*zip(x[1::2],x[0::2]))]
>>> a = [1, 2, 3, 4, 5, 6]
>>> sum([[x+1,x] for x in a if x&1 == True],[])
[2, 1, 4, 3, 6, 5]
EDIT: Some further explanation was requested:
The code steps through each element in the list a and, if the element is odd (x&1 == True) it puts that element and the next element into a list in reverse order ([x+1,x]).
With out the sum(...,[]) function we would have
[[2, 1], [4, 3], [6, 5]]
The sum(...,[]) function removes the internal square brackets giving
[2, 1, 4, 3, 6, 5]
This can be done more generally by using the index of the list rather than its value:
>>> a = [1, 2, 3, 4, 5, 6]
>>> sum([[a[x],a[x-1]] for x in range(len(a)) if x&1 == True],[])
[2, 1, 4, 3, 6, 5]
However, this will remove the last element of the list if its length is not even.

python sorting two lists

I am trying to sort two lists together:
list1 = [1, 2, 5, 4, 4, 3, 6]
list2 = [3, 2, 1, 2, 1, 7, 8]
list1, list2 = (list(x) for x in zip(*sorted(zip(list1, list2))))
Anyway, doing this gives me on output
list1 = [1, 2, 3, 4, 4, 5, 6]
list2 = [3, 2, 7, 1, 2, 1, 8]
while I would want to keep the initial order for equal number 4 in the first list: what I want is
list1 = [1, 2, 3, 4, 4, 5, 6]
list2 = [3, 2, 7, 2, 1, 1, 8]
What do I have to do? I wouldn't want to use loop for bubble-sorting. Any help appreciated.
Use a key parameter for your sort that only compares the first element of the pair. Since Python's sort is stable, this guarantees that the order of the second elements will remain the same when the first elements are equal.
>>> from operator import itemgetter
>>> [list(x) for x in zip(*sorted(zip(list1, list2), key=itemgetter(0)))]
[[1, 2, 3, 4, 4, 5, 6], [3, 2, 7, 2, 1, 1, 8]]
Which is equivalent to:
>>> [list(x) for x in zip(*sorted(zip(list1, list2), key=lambda pair: pair[0]))]
[[1, 2, 3, 4, 4, 5, 6], [3, 2, 7, 2, 1, 1, 8]]
The trick here is that when Python does tuple comparisons, it compares the elements in order from left to right (for example, (4, 1) < (4, 2), which is the reason that you don't get the ordering you want in your particular case). That means you need to pass in a key argument to the sorted function that tells it to only use the first element of the pair tuple as its sort expression, rather than the entire tuple.
This is guaranteed to retain the ordering you want because:
sorts are guaranteed to be stable. That means that when multiple records have the same key, their original order is preserved.
(source)
>>> list1 = [1, 2, 5, 4, 4, 3, 6]
>>> list2 = [3, 2, 1, 2, 1, 7, 8]
>>>
>>> list1, list2 = (list(x) for x in zip(*sorted(zip(list1, list2), key=lambda pair: pair[0])))
>>>
>>> print list1
[1, 2, 3, 4, 4, 5, 6]
>>> print list2
[3, 2, 7, 2, 1, 1, 8]
In you code the sorting is performed basing on the first and the second elements of the tuples, so the resulting second list elements are in the sorted order for the same elements of the first list.
To avoid sorting based on the second list, just specify that only the elements from the first list should be used in the comparison of the tuples:
>>> from operator import itemgetter
>>> list1, list2 = (list(x) for x in zip(*sorted(zip(list1, list2),key=itemgetter(0))))
>>> list1, list2
([1, 2, 3, 4, 4, 5, 6], [3, 2, 7, 2, 1, 1, 8])
itemgetter(0) takes the first element from each tuple, which belongs to the first list.

Access certain elements of a list

Can't figure out how to do this in a pretty way :
I have a list of n elements,
I want to access every m elements of the list.
For example : [1, 2, 3, 4, 5] and m = 2 would give
[2, 4]
I can do it simply with a loop, but ins't there a more "pythonic" way?
Thanks by advance !
EDIT :
Seems like I forgot something.
I want, not only get those values but modify them.
I tried slicing a[::2] = 3, but it doesn't work. . .
I'm searching for something similar
Slicing syntax does this for you:
>>> my_list = range(10)
>>> my_list
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> my_list[::2]
[0, 2, 4, 6, 8]
>>> my_list[1::2]
[1, 3, 5, 7, 9]
Here's a way to wrap a list to get the original assignment behavior you wanted, but I'm not sure I'd recommend it:
class AssignableSlice(list):
def __setitem__(self, i, v):
if isinstance(i, slice):
for ii in xrange(*i.indices(len(self))):
self[ii] = v
else:
super(AssignableSlice, self).__setitem__(i, v)
a = AssignableSlice(range(10))
print a
a[::2] = 3
print a
a[1::3] = 99
print a
produces:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[3, 1, 3, 3, 3, 5, 3, 7, 3, 9]
[3, 99, 3, 3, 99, 5, 3, 99, 3, 9]
Ned's answer shows how to use slices to access a portion of the list. You can also assign to a slice, but you need to assign a list to the slice, for example:
>>> my_list = range(5)
>>> my_list
[0, 1, 2, 3, 4]
>>> my_list[::2]
[0, 2, 4]
>>> my_list[::2] = [0, 0, 0]
>>> my_list
[0, 1, 0, 3, 0]
Note that when the step in your slice is anything besides the default of 1 the list that you assign needs to be the same length, however with a default step you can actually change the size of the list with slice assignment:
>>> my_list = range(5)
>>> my_list
[0, 1, 2, 3, 4]
>>> my_list[:1]
[0]
>>> my_list[:1] = [4, 3, 2] # replace the first item with 3 new items
>>> my_list
[4, 3, 2, 1, 2, 3, 4]
>>> my_list[2:5]
[2, 1, 2]
>>> my_list[2:5] = [] # remove the middle three items from the list
>>> my_list
[4, 3, 3, 4]
I juste found a way to do what I want using slicing.
The following :
candidates[::2] = [1] * len(candidates[::2])
will replace every 2 elements of candidates by 1

Categories