Repeat each elements based on a list of values - python

Is there a Python builtin that repeats each element of a list based on the corresponding value in another list? For example A in list x position 0 is repeated 2 times because of the value 2 at position 0 in the list y.
>>> x = ['A', 'B', 'C']
>>> y = [2, 1, 3]
>>> f(x, y)
['A', 'A', 'B', 'C', 'C', 'C']
Or to put it another way, what is the fastest way to achieve this operation?

Just use a simple list comprehension:
>>> x = ['A', 'B', 'C']
>>> y = [2, 1, 3]
>>> [x[i] for i in range(len(x)) for j in range(y[i])]
['A', 'A', 'B', 'C', 'C', 'C']
>>>

One way would be the following
x = ['A', 'B', 'C']
y = [2, 1, 3]
s = []
for a, b in zip(x, y):
s.extend([a] * b)
print(s)
result
['A', 'A', 'B', 'C', 'C', 'C']

from itertools import chain
list(chain(*[[a] * b for a, b in zip(x, y)]))
['A', 'A', 'B', 'C', 'C', 'C']
There is itertools.repeat as well, but that ends up being uglier for this particular case.

Try this
x = ['A', 'B', 'C']
y = [2, 1, 3]
newarray = []
for i in range(0,len(x)):
newarray.extend(x[i] * y[i])
print newarray

Related

Filter list using duplicates in another list

I have two equal-length lists, a and b:
a = [1, 1, 2, 4, 5, 5, 5, 6, 1]
b = ['a','b','c','d','e','f','g','h', 'i']
I would like to keep only those elements from b, which correspond to an element in a appearing for the first time. Expected result:
result = ['a', 'c', 'd', 'e', 'h']
One way of reaching this result:
result = [each for index, each in enumerate(b) if a[index] not in a[:index]]
# result will be ['a', 'c', 'd', 'e', 'h']
Another way, invoking Pandas:
import pandas as pd
df = pd.DataFrame(dict(a=a,b=b))
result = list(df.b[~df.a.duplicated()])
# result will be ['a', 'c', 'd', 'e', 'h']
Is there a more efficient way of doing this for large a and b?
You could try if this is faster:
firsts = {}
result = [firsts.setdefault(x, y) for x, y in zip(a, b) if x not in firsts]

Python Inline Generator

I'm attempting to interleave a value into a list.
interleave(1, ['A', 'B', 'C']) -> [1, 'A', 1, 'B', 1, 'C']
There are a number of ways to solve this problem, but I thought more_itertools.interleave would be the most readable. However to use this function I need to create a generator that yields 1 forever. Clearly this can be done with
def gen1():
while True:
yield 1
but this feels more complicated than necessary.
Is there an elegant way to replace ... in the snippet below to create an inline generator such that
res = more_itertools.interleave(..., ['A', 'B', 'C'])
assert list(res) == [1, 'A', 1, 'B', 1, 'C']
... = (1 for _ in ['A', 'B', 'C']) clearly works, but I wouldn't call it elegant.
itertools.repeat. I don't know how interleave is implemented, but you can do the same thing with chain and zip:
from itertools import chain, repeat
print(list(chain.from_iterable(zip(repeat(1), ['A', 'B', 'C']))))
# [1, 'A', 1, 'B', 1, 'C']
You can also use a list comprehension like this:
def interleave(value, lst):
return [j for i in lst for j in (value, i)]
So that interleave(1, ['A', 'B', 'C']) returns:
[1, 'A', 1, 'B', 1, 'C']
def interleave(a,list1):
newlist=[]
for x in list1:newlist.extend([a,x])
return newlist
print(interleave(1,['A','B','C']))
prints
[1, 'A', 1, 'B', 1, 'C']

how to match value of 1st list with the indexes of 2nd list in python

I am trying to match the value of 1st list with the indexes of 2nd list and if value and indexes match then in the result it will produce matches of the index value.
A = [0,2,0,5,2,1,1] # value of list 1
B = ['A', 'B', 'C', 'D'] # value of 2nd list
the result should be,
res = ['A', 'C', 'A', 'C', 'B', 'B']
Try the code below,
A = [0, 2, 0, 5, 2, 1, 1] # values of list 1
B = ['A', 'B', 'C', 'D'] # values of list 2
res = [B[i] for i in A if i<len(B)]
res
Output
['A', 'C', 'A', 'C', 'B', 'B']
A = [0,2,0,5,2,1,1] # value of list 1
B = ["A", "B", "C", "D"] # value of 2nd list
new_list = []
for val in A:
if val < len(B) - 1:
new_list.append(B[val])
print(new_list)
Results:
['A', 'C', 'A', 'C', 'B', 'B']
A = [0,2,0,5,2,1,1] # value of list 1
B = ['A', 'B', 'C', 'D']
size_minus_1 = len(B) - 1
result = []
for i in A:
if i < size_minus_1:
result.append(B[i])
print(result)

Get right label using indices?

Really stupid question as I am new to python:
If I have labels = ['a', 'b', 'c', 'd'],
and indics = [2, 3, 0, 1]
How should I get the corresponding label using each index so I can get: ['c', 'd', 'a', 'b']?
There are a few alternatives, one, is to use a list comprehension:
labels = ['a', 'b', 'c', 'd']
indices = [2, 3, 0, 1]
result = [labels[i] for i in indices]
print(result)
Output
['c', 'd', 'a', 'b']
Basically iterate over each index and fetch the item at that position. The above is equivalent to the following for loop:
result = []
for i in indices:
result.append(labels[i])
A third option is to use operator.itemgetter:
from operator import itemgetter
labels = ['a', 'b', 'c', 'd']
indices = [2, 3, 0, 1]
result = list(itemgetter(*indices)(labels))
print(result)
Output
['c', 'd', 'a', 'b']

Duplicate elements in a list [duplicate]

This question already has answers here:
Repeating elements of a list n times
(14 answers)
Closed 7 months ago.
I have a list in Python:
l = ['a', 'c', 'e', 'b']
I want to duplicate each element immediately next to the original.
ll = ['a', 'a', 'c', 'c', 'e', 'e', 'b', 'b']
The order of the elements should be preserved.
>>> l = ['a', 'c', 'e', 'b']
>>> [x for pair in zip(l,l) for x in pair]
['a', 'a', 'c', 'c', 'e', 'e', 'b', 'b']
Or
>>> from itertools import repeat
>>> [x for item in l for x in repeat(item, 2)]
['a', 'a', 'c', 'c', 'e', 'e', 'b', 'b']
This is old but I can't see the straightforward option here (IMO):
[ item for item in l for repetitions in range(2) ]
So for the specific case:
>>> l = ['a', 'c', 'e', 'b']
l = ['a', 'c', 'e', 'b']
>>> [ i for i in l for r in range(2) ]
[ i for i in l for r in range(2) ]
['a', 'a', 'c', 'c', 'e', 'e', 'b', 'b']
>>>
And generalizing:
[ item for item in l for _ in range(r) ]
Where r is the quantity of repetitions you want.
So this has a O(n.r) space and time complexity, is short, with no dependencies and also idiomatic.
import itertools
ll = list(itertools.chain.from_iterable((e, e) for e in l))
At work:
>>> import itertools
>>> l = ['a', 'c', 'e', 'b']
>>> ll = list(itertools.chain.from_iterable((e, e) for e in l))
>>> ll
['a', 'a', 'c', 'c', 'e', 'e', 'b', 'b']
As Lattyware pointed out, in case you want more than just double the element:
from itertools import chain, repeat
ll = list(chain.from_iterable(repeat(e, 2) for e in l))
Try this
for i in l:
ll.append(i)
ll.append(i)
Demo
It will just do your work but it's not an optimized way of doing this.
use the ans. posted by #Steven Rumbalski
Here's a pretty easy way:
sum(zip(l, l), tuple())
It duplicates each item, and adds them to a tuple. If you don't want a tuple (as I suspect), you can call list on the the tuple:
list(sum(zip(l, l), tuple()))
A few other versions (that yield lists):
list(sum(zip(l, l), ()))
sum([list(i) for i in zip(l, l)], [])
sum(map(list, zip(l, l)), [])
Pandas gives a method for duplicated elements:
import pandas as pd
l = pd.Series([2, 1, 3, 1])
print(l.duplicated())
>>>0 False
1 False
2 False
3 True
dtype: bool
print('Has list duplicated ? :', any(l.duplicated()))
>>>Has list duplicated ? : True

Categories

Resources