How to duplicate a specific value in a list/array?

Viewed 1092

Any advice on how to repeat a certain value in an array in Python? For instance, I want to repeat only 2 in array_a:

array_a = [1, 2, 1, 2, 1, 1, 2]

Wanted outcome is: I repeat each 2 and leave the 1:

array_a = [1, 2, 2, 1, 2, 2, 1, 1, 2, 2]  # only the `2` should be repeated

I tried numpy and I could duplicate the entire array but not a certain value.

9 Answers

If you're interested in a numpy solution, you can repeat an array on itself using np.repeat.

>>> import numpy as np
>>> np.repeat(array_a, array_a)
array([1, 2, 2, 1, 2, 2, 1, 1, 2, 2])

This works only if you haves 1s and 2s in your data. For a generic solution, consider

>>> n_repeats = 2
>>> temp = np.where(np.array(array_a) == 2, n_repeats, 1)
>>> np.repeat(array_a, temp)
array([1, 2, 2, 1, 2, 2, 1, 1, 2, 2])

May be you can use dictionary to each unique element and number of times it needs to be repeated. Then using list comprehension to create array:

array_a = [1,2,1,2,1,1,2]

repeat_times = {1:1, 2:2} # 1 is 1 time and 2 is repeated two times

result = [i for i in array_a for j in range(repeat_times[i])]
print(result) 

Output:

[1, 2, 2, 1, 2, 2, 1, 1, 2, 2]

If you convert this to a list, you can loop through it, and if it matches your criteria, add an extra version. For example:

a = [1,2,1,2,1,1,2]
long_a = []
for x in a:
    long_a.append(x)
    if x == 2:
       long_a.append(x)

This seems a good use-case for a generator:

>>> def repeater(iterable, repeat_map):
...     for value in iterable:
...         for i in range(repeat_map.get(value, 1)):
...             yield value
...             
>>> array_a = [1,2,1,2,1,1,2]
>>> list(repeater(array_a, repeat_map={2: 2}))
[1, 2, 2, 1, 2, 2, 1, 1, 2, 2]

An attempt using comprehensions.

array = [1, 2, 1, 2, 1, 1, 2]

element_to_repeat = 2

result = [
    repeats_element
    for repeats in
        ((element,)*2 if element == element_to_repeat else (element,) for element in array)
    for repeats_element in repeats
]

It basically spits out tuples, "repeats", which contain the element once if it's not the element to repeat, or twice if it's the element to repeat. Then all of the elements of these "repeats" tuples are flattened into the answer.

Here is a handy one-liner using itertools and list comprehension with if and else in it. First it makes a nested list (to have the ability to repeat items on a certain position) and then it will simply flatten it at the end using .chain()-method:

from itertools import chain
array_a = [1, 2, 1, 2, 1, 1, 2]

list(chain.from_iterable([[item, item] if item == 2 else [item] for item in array_a]))
[1, 2, 2, 1, 2, 2, 1, 1, 2, 2]  # output

The specific value to double is inside the if-statement. Using multipliers (instead of [item, item]) and a variable (instead of 2) would make this easily more generic, see this for example:

from itertools import chain

def repeat_certain_value(array, val, n):
    return list(chain.from_iterable(([i] * n if i == val else [i] for i in array)))

repeat_certain_value([1, 2, 1, 2, 1, 1, 2], 2, 2)
[1, 2, 2, 1, 2, 2, 1, 1, 2, 2]  # output

repeat_certain_value([0, -3, 1], -3, 5)
[0, -3, -3, -3, -3, -3, 1]  # output

While this approach is a handy one-liner using builtin libraries, the approach from coldspeed is faster:

%timeit for x in range(1000): repeat_certain_value([1, 1, 1, 2, 2, 2, 3, 3, 3] * 100, 2, 2)
10 loops, best of 3: 165 ms per loop

%timeit for x in range(1000): coldspeeds_solution([1, 1, 1, 2, 2, 2, 3, 3, 3] * 100, 2, 2)
10 loops, best of 3: 100 ms per loop

Using a generator.

array = [1, 2, 1, 2, 1, 1, 2]

element_to_repeat = 2

def add_repeats(array, element_to_repeat):
    for element in array:
        if element == element_to_repeat:
            yield element
            yield element
        else:
            yield element

result = list(add_repeats(array, element_to_repeat))

Can try a list comprehension and create a flat function:

array_a = [1, 2, 1, 2, 1, 1, 2]
def flat(l):
   newl=[]
   for i in l:
      if isinstance(i,list):
         newl.extend(i)
      else:
         newl.append(i)
   return newl
print(flat([[i]*2 if i==2 else i for i in array_a]))

Output:

[1, 2, 2, 1, 2, 2, 1, 1, 2, 2]
Related