-1

I have a function in which:

Given a list of Python values xs and a non-negative integer n, construct and return a copy of xs but with each value replicated n times. Do NOT modify the original list 'xs'

To do this, I created some small code that multiplied the list xs and then sorted it.

def replicate(xs,n): xscopy = sorted(n * xs) return xscopy

This code will result in a function input like "replicate([1,2,2,3],2)" to output as [1,1,2,2,2,2,3,3] which is correct. Note how the correct output has the numbers' places matching.

However, when a negative number is in the list, the 'sort' function sees the negative number as smaller than the positive numbers and shifts the position of the negative number from where it was originally on the list.

For example: replicate([1,-1,2,1],2) outputs to [-1,-1,1,1,1,1,2,2] rather than, the correct version, [1,1,-1,-1,2,2,1,1].

Notice how the negative 1 shifted?

I am required to use a loop of some sort (while or for) for this task and I can't figure out how I could incorporate a loop that would both preserve the positions of the numbers and append the numbers properly into a new list (a new list that contains both the original xs, and the duplicates, in the same order as the original.

EDIT: I should add that list comprehension is restricted for this task

Prithvi Boinpally
  • 427
  • 1
  • 9
  • 23
  • Sorry maybe I'm missing something here, but why exactly are you sorting it? – miradulo Mar 07 '17 at 02:21
  • 2
    As mitch said, both of your examples are being sorted with the `sorted()` function. You should avoid that if you don't want the order to change. – Jim Factor Mar 07 '17 at 02:23
  • I'm sorting it because if I didn't, the output for, say, "replicate([1,2,3],2)" would be "[1,2,3,1,2,3]" instead of "[1,1,2,2,2,2,3,3]" since I am multiplying the list as a whole. – Prithvi Boinpally Mar 07 '17 at 02:25

4 Answers4

3

You could just use a nested list comprehension if you want to keep the order of the elements from the original list, this will take each element from the list xs, repeat it n times and then go for the next element and so on:

xs = [1,-1,2,1]
n = 2

[x for x in xs for _ in range(n)]
# [1, 1, -1, -1, 2, 2, 1, 1]

xs = [1,2,3]
n = 2
[x for x in xs for _ in range(n)]
# [1, 1, 2, 2, 3, 3]
Psidom
  • 209,562
  • 33
  • 339
  • 356
3
def replicate(xs, n):
  return [item for item in xs for repeat in range(n)]
Đào Minh Hạt
  • 2,742
  • 16
  • 20
1

You don't need to sort it. For each number in the list, loop n times and add it to a new list, so you preserve the original list and still get what you wanted.

def replicate(xs,n):
    result = []
    for num in xs:
        for _ in range(n):
            result.append(num)

    return result

A cleaner way would be using list comprehension return [num for num in xs for _ in range(n)]

Either way, output of replicate([1,-1,2,1],2) is [1, 1, -1, -1, 2, 2, 1, 1]

user3813674
  • 2,553
  • 2
  • 15
  • 26
1

You can create a single-element list, and then multiply it. Once you have an n-element list, you can extend() the result list with that portion of the result.

result = []
for item in xs:
    nitems = [item] * n
    result.extend(nitems)

The functools.reduce function can be used for this:

import functools
return functools.reduce((lambda a,b: a + [b]*n), xs, [])

The sum builtin can do something similar:

return sum( [ [x]*n for x in xs], [])

The itertools.chain function can paste together a bunch of iterables, so you could just multiply the values into a bunch of sub-lists and pass them to it:

import itertools
return list(itertools.chain(*[ [x]*n for x in xs ]))

Or, without the splat (*) operator:

import itertools
return list(itertools.chain.from_iterable([[x]*n for x in xs])

Or, you could zip the original list against itself, then flatten those tuples. (This would be good for long lists, especially if you could just return the iterable instead of a list):

import itertools
return list(itertools.chain.from_iterable(zip(*[iter(xs) for _ in range(n)])))
aghast
  • 14,785
  • 3
  • 24
  • 56