10

Suppose

A = [9, 5, 34, 33, 32, 31, 300, 30, 3, 256]

I want to sort only a particular section in a list. For example, here I want to sort only [300, 30, 3] so that overall list becomes:

A = [9, 5, 34, 33, 32, 31, 3, 30, 300, 256]

Suppose B = [300, 30, 400, 40, 500, 50, 600, 60] then after sorting it should be B = [30, 300, 40, 400, 50, 500, 60, 600].

Main idea if the leftmost digit is same 300, 30, 30 and right most digits contain only zeros then we should arrange it in increasing order.

Another example:

A = [100, 10, 1, 2000, 20, 2]

After sorting it should be A = [1, 10, 100, 2, 20, 2000]

Could anyone suggest some techniques to approach such issue. The values in my list will always be arranged in this way [200, 20, 2, 300, 30, 3, 400, 40, 4].

Code:

nums = [3, 30, 31, 32, 33, 34, 300, 256, 5, 9]
nums = sorted(nums, key=lambda x: str(x), reverse=True)
print nums
>> [9, 5, 34, 33, 32, 31, 300, 30, 3, 256]

But my final output should be [9, 5, 34, 33, 32, 31, 3, 30, 300 256].

Here is a big example:

A = [9, 5, 100, 10, 30, 3, 265, 200, 20, 2]

After sorting it should be:

A = [9, 5, 10, 100, 3, 30, 265, 2, 20, 200]
Mazdak
  • 105,000
  • 18
  • 159
  • 188
python
  • 4,403
  • 13
  • 56
  • 103
  • 3
    You can make this a good question by showing your code.And let us know that what you have tried so far. – Mazdak Nov 20 '15 at 09:02
  • 3
    `lambda x: str(x)` is just `str`. – TigerhawkT3 Nov 20 '15 at 09:11
  • still not clear to me, in the very last example [3, 30, 31, 32, 33, 34, 300, 256, 5, 9], what do you expect as result? – fransua Nov 20 '15 at 09:11
  • 1
    @fransua The expected result is in the second last line. – Psytho Nov 20 '15 at 09:12
  • Related: [Python: split a list based on a condition?](http://stackoverflow.com/questions/949098/python-split-a-list-based-on-a-condition) – GingerPlusPlus Nov 20 '15 at 09:20
  • What is the correct output for [3, 20, 30, 2]? – VPfB Nov 20 '15 at 09:34
  • My list will always be arranged in [20, 2, 30,3] so here answer will be [2, 20, 3, 30] – python Nov 20 '15 at 09:36
  • @python: why do you need it? – GingerPlusPlus Nov 20 '15 at 09:37
  • @python Have you found an answer. – Akshay Hazari Nov 20 '15 at 10:50
  • How should the rest of the numbers be arranged? In your example you have `nums = [3, 30, 31, 32, 33, 34, 300, 256, 5, 9]` and you say that "[your] final output should be `[9, 5, 34, 33, 32, 31, 3, 30, 300 256]`". Here you are sorting *all* the values in the list, with a special rule for a subset of values, which is at odds with the title of the question. – A.P. Nov 20 '15 at 13:15
  • Furthermore, sorting a subset of a string is well-defined only when that subset is contiguous: if you want to sort only `3`,`30`, and `300` in `[3, 30, 31, 32, 33, 34, 300, 256, 5, 9]` should the result be `[3, 30, 300, 31, 32, 33, 34, 256, 5, 9]`? Or maybe `[31, 32, 33, 34, 3, 30, 300, 256, 5, 9]`? Or something else altogether? – A.P. Nov 20 '15 at 13:16
  • @A.P. Seems like you misunderstood the question. My list will always be arranged in a certain way like `[ 9, 5, 10, 300, 30, 3], or [400, 40, 4]`. All numbers with the leftmost digit same will be arranged contiguous. – python Nov 20 '15 at 19:51
  • @A.P. Run your list through this line `sorted(nums, key=lambda x: str(x), reverse=True)` and see the output – python Nov 20 '15 at 19:52
  • Well... you start your question with "I want to sort only a *particular section* in a list" (emphasis mine) but the function `sorted(nums, key=lambda x: str(x), reverse=True)` sorts *all* the list, not just part of it. Could you please rephrase your question to make explicitly clear what you want? Note that even having all the numbers with the left-most digit in contiguous places isn't enough to avoid issues when sorting only part of a list, see for example `[3, 31, 392, 30, 312]`. – A.P. Nov 20 '15 at 20:31
  • How in your question does this A = [9, 5, 100, 10, 30, 3, 265, 200, 20, 2] become A = [9, 5, 10, 100, 3, 30, 265, 2, 20, 200] , shouldn't it be this [9, 5, 3, 265, 30, 2, 20, 200, 10, 100] instead – Akshay Hazari Nov 21 '15 at 04:11

6 Answers6

7

Since each expected sequence is contains the numbers which are a common coefficient of power of then, You can use a scientific_notation function which returns the common coefficient.Then you can categorize your numbers based on this function and concatenate them.

>>> from operator import itemgetter
>>> from itertools import chain,groupby

>>> def scientific_notation(number):
...     while number%10 == 0:
...         number = number/10
...     return number

>>> A = [9, 5, 34, 33, 32, 31, 300, 30, 3, 256]
>>> G=[list(g) for _,g in groupby(A,key=scientific_notation)] 
>>> list(chain.from_iterable(sorted(sub) if len(sub)>1 else sub for sub in G))
[9, 5, 34, 33, 32, 31, 3, 30, 300, 256]

Note that since we are categorizing the numbers based on coefficient of power of then if the length of a sub-list be more than 1 means that it's a sequence of expected numbers which need to be sort.So instead of checking the length of each sequence you can simply apply the sort on all the generators in group by:

>>> list(chain.from_iterable(sorted(g) for _,g in groupby(A,key=scientific_notation)))
[9, 5, 34, 33, 32, 31, 3, 30, 300, 256]
Mazdak
  • 105,000
  • 18
  • 159
  • 188
3

Really got twisted with this one , still don't know if it would work for all cases.

nums = [3, 30, 31, 32, 33, 34, 300, 256, 5, 9]
map(lambda x: x[1],sorted(zip(range(0,len(nums)),sorted(nums, key=lambda x: str(x), reverse=True)), key=lambda x: str(x[1]) if not str(x[1]).endswith('0') else str(str(x[1]-1)[0])+str(x[0]), reverse=True))

O/P : [9, 5, 34, 33, 32, 31, 3, 30, 300, 256]

Now I guess it would work with everything:

Earlier one wouldn't work with this nums = [30, 3, 31, 32, 33, 34, 330, 256, 5, 9]

nums = [30, 3, 31, 32, 33, 34, 330, 256, 5, 9]
map(lambda x: x[1],sorted(zip(range(0,len(nums)),sorted(nums, key=lambda x: str(x), reverse=True)), key=lambda x: str(x[1]) if not str(x[1]).endswith('0') else str(int(str(x[1]).strip("0"))-1)+str(x[0]), reverse=True))

O/P: [9, 5, 34, 33, 330, 32, 31, 3, 30, 256]

Here what I have done is taking your sorted list function , applied a zip after enumerating it So I would get [(0, 9), (1, 5), (2, 34), (3, 33), (4, 32), (5, 31), (6, 300), (7, 30), (8, 3), (9, 256)] for your input then if an element endswith a zero I would remove trailing zeros and subtract 1 and then convert it to string and append sorted index to the string which would give me a sorted list as per your case.

For e.g

Step one : zip index [(0, 9), (1, 5), (2, 34), (3, 33), (4, 32), (5, 31), (6, 300), (7, 30), (8, 3), (9, 256)]

Step two : strip trailing zeros [(0, 9), (1, 5), (2, 34), (3, 33), (4, 32), (5, 31), (6, 3), (7, 3), (8, 3), (9, 256)]

Step three : subtract 1 from those elements which had trailing zeros [(0, 9), (1, 5), (2, 34), (3, 33), (4, 32), (5, 31),(6, 3-1), (7, 3-1) (8, 3), (9, 256)]

Step four : if had trailing zeros sort them by reversed index ie first value in tuple [(0, 9), (1, 5), (2, 34), (3, 33), (4, 32), (5, 31), (8, 3), (7, 2), (6, 2), (9, 256)]

Step five : get sorted [9, 5, 34, 33, 32, 31, 3, 30, 300, 256]

OR :

More correct and Simpler solution :

sorted(map(lambda x : str(x),[9, 5, 100, 10, 30, 3, 265, 200, 20, 2]),key=lambda x : x.strip("0")+x.rjust(len(x)+(len(x)-len(x.strip("0"))),'0'),reverse=True)
Akshay Hazari
  • 3,186
  • 4
  • 48
  • 84
2

You can accomplish this by padding with zeros:

>>> nums = [3, 30, 31, 32, 33, 34, 300, 256, 5, 9]
>>> sorted(nums, key=lambda x: str(x).ljust(10,' '), reverse=True)
[9, 5, 34, 33, 32, 31, 3, 30, 300, 256]

EDIT: Change '0' in just to ' ' so that it comes lexicographically before '0' and does not compare equal with it (that it worked was a bit lucky, I think).

BallpointBen
  • 9,406
  • 1
  • 32
  • 62
1

This solution is not exactly what you ask for, but may help:

nums = [3, 30, 31, 10, 100, 32, 33, 1, 34, 300, 256, 5, 9]
sorted(nums, key=lambda x: str((x*10 in nums or x/10. in nums)*x))

> [31, 32, 33, 34, 256, 5, 9, 1, 10, 100, 3, 30, 300]
fransua
  • 1,559
  • 13
  • 30
1

This is generic with any continous numbers.

import re
k=[300, 30, 400, 40, 500, 50, 600, 60]
i=0
j=0
t1=[]
t2=[]
while i < len(k):
    a=re.match(r"(\d)0*$|",str(k[i])).group(1)
    j=i+1
    t2.append(k[i])
    while a and j<len(k):
        b=re.match(a+r"0*$",str(k[j]))
        if b:
            t2.append(k[j])
            j=j+1
        else:
            break
    if len(t2)>1:
        t2.sort()

        [t1.append(m) for m in t2]
        t2=[]
        i=j-1
    else:
        t1.append(k[i])
        t2=[]
    i=i+1
print t1

Output:[30, 300, 40, 400, 50, 500, 60, 600]

vks
  • 67,027
  • 10
  • 91
  • 124
1

how to accomplish:

1) try comparing list[n] with list[n+1] when % of list[n+1]%list[n]==0(remainder) 2) if yes, interchange their index numbers

You are done