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);
}
}
Sorting a list of strings based on numeric order of numeric part
You could use the re
module to split each string into a tuple of characters and grouping the digits into one single element. Something like r'(\d+)|(.)'
. The good news with this regex is that it will return separately the numeric and non numeric groups.
As a simple key, we could use:
def key(x):
# the tuple comparison will ensure that numbers come before letters
return [(j, int(i)) if i != '' else (j, i)
for i, j in re.findall(r'(\d+)|(.)', x)]
Demo:
lst = ['a1a', 'a2a', 'a5b', 'a10a', 'b1a', 'abc']
print(sorted(lst, key=key)
gives:
['a1a', 'a2a', 'a5b', 'a10a', 'abc', 'b1a']
If you want a more efficient processing, we could compile the regex only once in a closure
def build_key():
rx = re.compile(r'(\d+)|(.)')
def key(x):
return [(j, int(i)) if i != '' else (j, i)
for i, j in rx.findall(x)]
return key
and use it that way:
sorted(lst, key=build_key())
giving of course the same output.
sort numbers numerically and strings alphabetically in an array perl
Divide into 2 lists, sort each individually, then combine back into 1 list.
use warnings;
use strict;
my @arr = qw(txt text anothertext 38.09 100.87 0.876);
my @word = sort {$a cmp $b} grep { /^[a-z]/i } @arr;
my @num = reverse sort {$a <=> $b} grep { !/^[a-z]/i } @arr;
my @sorted_as = (@word, @num);
print "@sorted_as\n";
Outputs:
anothertext text txt 100.87 38.09 0.876
To get des also, add these lines:
@word = reverse @word;
my @sorted_des = (@word, @num);
print "@sorted_des\n";
Sort a list of strings which contains float numbers
The question arises why you have a string
in the first place if you store a double
. You should parse them as soon as possible (or prevent that they are strings where you load them).
However, you can always try to parse them afterwards:
List<MyObject> sortedList = myUnsortedList
.OrderyDescending(x => double.Parse(x.Number))
.ToList();
If you dont know if they have all a valid format you can use double.TryParse
. Maybe you need to pass the appropriate CultureInfo
to double.Parse
(for example if your current culture uses comma as decimal separator).
How can I get a sorted `List string ` based on an associated numeric index
It's not working after 10th index.
That is because List().Sort invoke string's comparison function.In string comparison "0" is less than "1", "1" is less than "11" and "12" is less than "2" etc.So it is not working after 10.
You can definition a sample comparison function as below:
public static int Compare(string a, string b)
{
return int.Parse(a.Substring(0, 15)).CompareTo(int.Parse(b.Substring(0, 15)));
}
and then invoke it in sort method:
stringList.Sort(Compare);
The prerequisite is that your format is satisfied that its first 15 characters can convert to an integer.
Sort on a string that may contain a number
The Alphanum Algorithm
From the website
"People sort strings with numbers differently than software. Most sorting algorithms compare ASCII values, which produces an ordering that is inconsistent with human logic. Here's how to fix it."
Edit: Here's a link to the Java Comparator Implementation from that site.
R: order a vector of strings with both character and numeric values both alphabetically and numerically
EDIT completely change the solution after OP clarification
You can extract the last 3 elements and order, and you create a data.frame:
dat = read.table(text=sub('.*:1:([0-9]+):([0-9]+):([0-9]+)','\\1|\\2|\\3',a),sep='|')
dat
V1 V2 V3
1 1102 14591 91480
2 1102 14592 3881
3 1102 14592 37103
4 1102 14592 37356
Then you order using 3 columns:
a[with(dat,order(V1,V2,V3))]
[1] "ILLUMINA:420:C2D7UACXX:1:1102:14591:91480" "ILLUMINA:420:C2D7UACXX:1:1102:14592:3881"
[3] "ILLUMINA:420:C2D7UACXX:1:1102:14592:37103" "ILLUMINA:420:C2D7UACXX:1:1102:14592:37356"
C# Sort string array alphabetically taking care of putting strings which start with capital letter first. first
You should specify the comparer, e.g. (Linq solution):
string[] source = new string[] {
"Lets",
"all",
"go",
"on",
"holiday",
"somewhere",
"very",
"cold",
};
// StringComparer.Ordinal: order by Ascii values; capital letters < small letters
var ordered = source
.OrderBy(item => item, StringComparer.Ordinal);
Console.Write(string.Join(", ", ordered));
Outcome:
Lets, all, cold, go, holiday, on, somewhere, very
To obtain the desired outcome (in case you insist on ordering), you can put
var result = string.Join("***", source
.OrderBy(item => item, StringComparer.Ordinal)
.First()
.Select(c => c)); // <- turn string into IEnumerable<char>
Console.Write(result);
Outcome:
L***e***t***s
In case you want to keep on using your current code, change Array.Sort(s);
into
Array.Sort(s, StringComparer.Ordinal);
LINQ OrderBy or Sort does not order correctly for integer string list?
This particular question comes up all the time and I'm pretty sure there are good duplicate questions here on Stack Overflow covering the topic. Please close the question as a proper duplicate and I'd be more than happy to delete my answer in response.
In the meantime...
The problem is us humans.
We see numbers so we think in numbers. To us, 1 is less than 12, and 12 is less than 100. No problems here.
The problem, however, is that we're asking a computer. And a computer is a bit more finicky. In particular, if we're asking a computer to do a alphabetical sort, it will invariably treat our "things" to sort as text. And this is where the problems occur. Or rather, this is where our expectations no longer match what the computer is going to do.
The computer, when asked to sort strings, sort them as any other string sort, character by character.
Let's look at the items:
1
100
12
To us, the natural sort order would be 1, 12, 100. Increasing order.
To the computer, asked to do a text sort, the natural order is different.
The reason is that it's going to compare strings one character at a time.
Broadly it is going to say "all strings that start with 1 is going to come before strings that start with 2", which means "1" and "100" is going to come before "2". This is exactly the same as saying "all words that start with the letter A comes before words that start with the letter B".
Then it's going to say "all strings that then have a 0 comes before strings that have a 1, 2, 3, etc. up to 9, including space", because this is how text sorting is done.
In other words, when you ask "Sort does not order correctly for integer string list?" the simple answer is "Well, no, because when you sort as text, the integer part is never considered".
Related Topics
How Exactly Do Static Fields Work Internally
How to Edit CSS Style of a Div Using C# in .Net
Why Does "Abcd".Startswith("") Return True
How to Get the Current Line Number
How to Directly Execute SQL Query in C#
How Does Native Implementation of Valuetype.Gethashcode Work
How to Run a Simple Bit of Code in a New Thread
Is Using a Mutex to Prevent Multiple Instances of the Same Program from Running Safe
Pinvoke for C Function That Returns Char *
How to Correctly Cast a Class to an Abstract Class When Using Type Generics
Creating a Comma Separated List from Ilist<String> or Ienumerable<String>
Right Click Context Menu for Datagridview
Which Radio Button in the Group Is Checked
How Would You Compare Two Xml Documents
ASP.NET File Download from Server
Filesystemwatcher with Samba on Linux
Extension Methods Must Be Defined in a Non-Generic Static Class