Сортировка буквенно-цифровой строки, содержащей десятичный символ в C #, выпуск с десятичными точками [дубликат]

Создайте псевдоним для gcc с вашим любимым включением.

alias mygcc='gcc -I /whatever/'
26
задан Default 9 April 2013 в 11:22
поделиться

10 ответов

Это потому, что упорядочение по умолчанию для строки является стандартным буквенно-цифровым словарным (лексикографическим) заказом, а ABC11 будет предшествовать ABC2, потому что упорядочение всегда происходит слева направо.

Чтобы получить то, что вы хотите, вы нужно поместить числовую часть в вашем предложении order, что-то вроде:

 var result = partNumbers.OrderBy(x => PadNumbers(x));

, где PadNumbers может быть определено как:

public static string PadNumbers(string input)
{
    return Regex.Replace(input, "[0-9]+", match => match.Value.PadLeft(10, '0'));
}

. Эти колодки нумеруют для любого числа (или числа), которые появляются во входной строке, так что OrderBy видит:

ABC0000000010
ABC0000000001
...
AB0000000011

Заполнение происходит только на клавише, используемом для сравнения. Исходные строки (без заполнения) сохраняются в результате.

Обратите внимание, что этот подход предполагает максимальное количество цифр для чисел на входе.

32
ответ дан Joey Adams 25 August 2018 в 14:59
поделиться

Вы можете использовать PInvoke для получения быстрого и хорошего результата:

class AlphanumericComparer : IComparer<string>
{
    [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
    static extern int StrCmpLogicalW(string s1, string s2);

    public int Compare(string x, string y) => StrCmpLogicalW(x, y);
}

Вы можете использовать его как AlphanumComparatorFast из вышеприведенного ответа.

3
ответ дан Alex Zhukovskiy 25 August 2018 в 14:59
поделиться

Нет естественного способа сделать это в .NET, , но посмотрите на это сообщение в блоге по естественной сортировке

. Вы можете поместить это в метод расширения и использовать это вместо OrderBy

1
ответ дан AndrewC 25 August 2018 в 14:59
поделиться

Вы можете PInvoke на StrCmpLogicalW (функция windows) сделать это. См. Здесь: Природный порядок сортировки в C #

3
ответ дан Dmitry Bychenko 25 August 2018 в 14:59
поделиться

Если вы хотите отсортировать список объектов по определенному свойству с помощью LINQ и пользовательского сопоставителя, такого как Dave Koelle , вы сделали бы что-то вроде этого:

...

items = items.OrderBy(x => x.property, new AlphanumComparator()).ToList();

...

Вам также нужно изменить класс Dave для наследования с System.Collections.Generic.IComparer<object> вместо базового IComparer, чтобы подпись класса стала:

...

public class AlphanumComparator : System.Collections.Generic.IComparer<object>
{

    ...

Лично я предпочитаю реализацию Джеймс Маккормак , поскольку он реализует IDisposable, хотя мой бенчмаркинг показывает, что он немного медленнее.

3
ответ дан John Meyer 25 August 2018 в 14:59
поделиться

Я не знаю, как это сделать в LINQ, но, возможно, вам это нравится:

Array.Sort(partNumbers, new AlphanumComparatorFast());

// Показывать результаты

foreach (string h in partNumbers )
{
Console.WriteLine(h);
}
-2
ответ дан Kurdish 25 August 2018 в 14:59
поделиться

Правильная реализация алфавитно-цифрового метода сортировки, который «работает просто», можно найти на сайте Dave Koelle . Версия C # здесь .

9
ответ дан ranieuwe 25 August 2018 в 14:59
поделиться
public class AlphanumComparatorFast : IComparer
{
    List<string> GetList(string s1)
    {
        List<string> SB1 = new List<string>();
        string st1, st2, st3;
        st1 = "";
        bool flag = char.IsDigit(s1[0]);
        foreach (char c in s1)
        {
            if (flag != char.IsDigit(c) || c=='\'')
            {
                if(st1!="")
                SB1.Add(st1);
                st1 = "";
                flag = char.IsDigit(c);
            }
            if (char.IsDigit(c))
            {
                st1 += c;
            }
            if (char.IsLetter(c))
            {
                st1 += c;
            }


        }
        SB1.Add(st1);
        return SB1;
    }



    public int Compare(object x, object y)
    {
        string s1 = x as string;
        if (s1 == null)
        {
            return 0;
        }
        string s2 = y as string;
        if (s2 == null)
        {
            return 0;
        }
        if (s1 == s2)
        {
            return 0;
        }
        int len1 = s1.Length;
        int len2 = s2.Length;
        int marker1 = 0;
        int marker2 = 0;

        // Walk through two the strings with two markers.
        List<string> str1 = GetList(s1);
        List<string> str2 = GetList(s2);
        while (str1.Count != str2.Count)
        {
            if (str1.Count < str2.Count)
            {
                str1.Add("");
            }
            else
            {
                str2.Add("");
            }
        }
        int x1 = 0; int res = 0; int x2 = 0; string y2 = "";
        bool status = false;
        string y1 = ""; bool s1Status = false; bool s2Status = false;
        //s1status ==false then string ele int;
        //s2status ==false then string ele int;
        int result = 0;
        for (int i = 0; i < str1.Count && i < str2.Count; i++)
        {
            status = int.TryParse(str1[i].ToString(), out res);
            if (res == 0)
            {
                y1 = str1[i].ToString();
                s1Status = false;
            }
            else
            {
                x1 = Convert.ToInt32(str1[i].ToString());
                s1Status = true;
            }

            status = int.TryParse(str2[i].ToString(), out res);
            if (res == 0)
            {
                y2 = str2[i].ToString();
                s2Status = false;
            }
            else
            {
                x2 = Convert.ToInt32(str2[i].ToString());
                s2Status = true;
            }
            //checking --the data comparision
            if(!s2Status && !s1Status )    //both are strings
            {
                result = str1[i].CompareTo(str2[i]);
            }
            else if (s2Status && s1Status) //both are intergers
            {
                if (x1 == x2)
                {
                    if (str1[i].ToString().Length < str2[i].ToString().Length)
                    {
                        result = 1;
                    }
                    else if (str1[i].ToString().Length > str2[i].ToString().Length)
                        result = -1;
                    else
                        result = 0;
                }
                else
                {
                    int st1ZeroCount=str1[i].ToString().Trim().Length- str1[i].ToString().TrimStart(new char[]{'0'}).Length;
                    int st2ZeroCount = str2[i].ToString().Trim().Length - str2[i].ToString().TrimStart(new char[] { '0' }).Length;
                    if (st1ZeroCount > st2ZeroCount)
                        result = -1;
                    else if (st1ZeroCount < st2ZeroCount)
                        result = 1;
                    else
                    result = x1.CompareTo(x2);

                }
            }
            else
            {
                result = str1[i].CompareTo(str2[i]);
            }
            if (result == 0)
            {
                continue;
            }
            else
                break;

        }
        return result;
    }
}

ИСПОЛЬЗОВАНИЕ этого класса:

    List<string> marks = new List<string>();
                marks.Add("M'00Z1");
                marks.Add("M'0A27");
                marks.Add("M'00Z0");
marks.Add("0000A27");
                marks.Add("100Z0");

    string[] Markings = marks.ToArray();

                Array.Sort(Markings, new AlphanumComparatorFast());
3
ответ дан Sathish adabala 25 August 2018 в 14:59
поделиться

Хорошо выглядит, что он делает лексикографическое упорядочение независимо от мелких или больших символов.

Вы можете попробовать использовать какое-то пользовательское выражение в этой лямбде, чтобы это сделать.

1
ответ дан Shekhar_Pro 25 August 2018 в 14:59
поделиться

Поскольку число символов в начале является переменной, регулярное выражение помогло бы:

var re = new  Regex(@"\d+$"); // finds the consecutive digits at the end of the string
var result = partNumbers.OrderBy(x => int.Parse(re.Match(x).Value));

Если было фиксированное количество символов префикса, то вы могли бы использовать метод Substring для извлечение, начиная с соответствующих символов:

// parses the string as a number starting from the 5th character
var result = partNumbers.OrderBy(x => int.Parse(x.Substring(4)));

Если числа могут содержать разделитель десятичных чисел или разделитель тысяч, то регулярное выражение должно также допускать эти символы:

var re = new Regex(@"[\d,]*\.?\d+$");
var result = partNumbers.OrderBy(x => double.Parse(x.Substring(4)));

Если строка, возвращаемая регулярным выражением или Substring, может быть недоступна с помощью int.Parse / double.Parse, используйте соответствующий вариант TryParse:

var re = new  Regex(@"\d+$"); // finds the consecutive digits at the end of the string
var result = partNumbers.OrderBy(x => {
    int? parsed = null;
    if (int.TryParse(re.Match(x).Value, out var temp)) {
        parsed = temp;
    }
    return parsed;
});
0
ответ дан Zev Spitz 25 August 2018 в 14:59
поделиться
Другие вопросы по тегам:

Похожие вопросы: