简体   繁体   中英

How do I keep the order of sorted numbers in a list the same in Python

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

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]
def replicate(xs, n):
  return [item for item in xs for repeat in range(n)]

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]

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)])))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM