How to Correctly Sort a String With a Number Inside

How to correctly sort a string with a number inside?

Perhaps you are looking for human sorting (also known as natural sorting):

import re

def atoi(text):
return int(text) if text.isdigit() else text

def natural_keys(text):
'''
alist.sort(key=natural_keys) sorts in human order
http://nedbatchelder.com/blog/200712/human_sorting.html
(See Toothy's implementation in the comments)
'''
return [ atoi(c) for c in re.split(r'(\d+)', text) ]

alist=[
"something1",
"something12",
"something17",
"something2",
"something25",
"something29"]

alist.sort(key=natural_keys)
print(alist)

yields

['something1', 'something2', 'something12', 'something17', 'something25', 'something29']

PS. I've changed my answer to use Toothy's implementation of natural sorting (posted in the comments here) since it is significantly faster than my original answer.


If you wish to sort text with floats, then you'll need to change the regex from one that matches ints (i.e. (\d+)) to a regex that matches floats:

import re

def atof(text):
try:
retval = float(text)
except ValueError:
retval = text
return retval

def natural_keys(text):
'''
alist.sort(key=natural_keys) sorts in human order
http://nedbatchelder.com/blog/200712/human_sorting.html
(See Toothy's implementation in the comments)
float regex comes from https://stackoverflow.com/a/12643073/190597
'''
return [ atof(c) for c in re.split(r'[+-]?([0-9]+(?:[.][0-9]*)?|[.][0-9]+)', text) ]

alist=[
"something1",
"something2",
"something1.0",
"something1.25",
"something1.105"]

alist.sort(key=natural_keys)
print(alist)

yields

['something1', 'something1.0', 'something1.105', 'something1.25', 'something2']

How to sort string with numbers in it numerically?

I think

val sortedList = data.sortedWith(compareBy(
{ it.listId },
{ it.name.substring(0, it.name.indexOf(' ')) },
{ it.name.substring(it.name.indexOf(' ') + 1).toInt() }
))

will work but it is not computationally efficient because it will call String.indexOf() many times.

If you have a very long list, you should consider making another list whose each item has String and Int names.

Sort string by multiple separated numbers

Try with sorted, supplying a custom key that uses re to extract all numbers from the path:

import re

>>> sorted(paths, key=lambda x: list(map(int,re.findall("(\d+)", x))))
['apple1/banana1',
'apple1/banana2',
'apple2/banana1',
'apple2/banana2',
'apple10/banana1/carrot1',
'apple10/banana1/carrot2',
'apple10/banana2/carrot1']

Sort list of string based on number in string

If you want to do this in the general case, I would try a natural sorting package like natsort.

from natsort import natsorted
my_list = ['image101.jpg', 'image2.jpg', 'image1.jpg']
natsorted(my_list)

Returns:

['image1.jpg', 'image2.jpg', 'image101.jpg']

You can install it using pip i.e. pip install natsort

How to sort first by letter then by number?

You can use a function to modify the sort key of each list item, without altering the original list contents:

def sort_key(text: str):
letter = text[0] # the first char
digits = text[1:] # everything after the first char
return (letter, int(digits))

>>> sws = ['C6', 'A4', 'B8', 'A8', 'B11', 'C3', 'C5']
>>> sorted(sws, key=sort_key)
['A4', 'A8', 'B8', 'B11', 'C3', 'C5', 'C6']

How to sort a list of strings numerically?

You haven't actually converted your strings to ints. Or rather, you did, but then you didn't do anything with the results. What you want is:

list1 = ["1","10","3","22","23","4","2","200"]
list1 = [int(x) for x in list1]
list1.sort()

If for some reason you need to keep strings instead of ints (usually a bad idea, but maybe you need to preserve leading zeros or something), you can use a key function. sort takes a named parameter, key, which is a function that is called on each element before it is compared. The key function's return values are compared instead of comparing the list elements directly:

list1 = ["1","10","3","22","23","4","2","200"]
# call int(x) on each element before comparing it
list1.sort(key=int)

Is there a way to sort string lists by numbers inside of the strings?

You can sort the list like this:

hi.sort();

(because numbers sort before letters in its implementation)

How do I sort strings alphabetically while accounting for value when a string is numeric?

Pass a custom comparer into OrderBy. Enumerable.OrderBy will let you specify any comparer you like.

This is one way to do that:

void Main()
{
string[] things = new string[] { "paul", "bob", "lauren", "007", "90", "101"};

foreach (var thing in things.OrderBy(x => x, new SemiNumericComparer()))
{
Console.WriteLine(thing);
}
}

public class SemiNumericComparer: IComparer<string>
{
/// <summary>
/// Method to determine if a string is a number
/// </summary>
/// <param name="value">String to test</param>
/// <returns>True if numeric</returns>
public static bool IsNumeric(string value)
{
return int.TryParse(value, out _);
}

/// <inheritdoc />
public int Compare(string s1, string s2)
{
const int S1GreaterThanS2 = 1;
const int S2GreaterThanS1 = -1;

var IsNumeric1 = IsNumeric(s1);
var IsNumeric2 = IsNumeric(s2);

if (IsNumeric1 && IsNumeric2)
{
var i1 = Convert.ToInt32(s1);
var i2 = Convert.ToInt32(s2);

if (i1 > i2)
{
return S1GreaterThanS2;
}

if (i1 < i2)
{
return S2GreaterThanS1;
}

return 0;
}

if (IsNumeric1)
{
return S2GreaterThanS1;
}

if (IsNumeric2)
{
return S1GreaterThanS2;
}

return string.Compare(s1, s2, true, CultureInfo.InvariantCulture);
}
}


Related Topics



Leave a reply



Submit