订单字符串如数字

时间:2019-03-29 12:57:28

标签: c# linq

我想对有时包含数字值的字符串列表进行排序

我的列表是这样的:

  • 卧室1
  • 卧室2
  • 10号卧室
  • 卫生间1
  • 卫生间2
  • 浴室10
  • 1灯
  • 1篇论文

如果我只是使用orderby: roomList.OrderBy(x => x.Name) 我得到以下列表:

  • 1灯
  • 1篇论文
  • 卫生间1
  • 浴室10
  • 卫生间2
  • 卧室1
  • 10号卧室
  • 卧室2

是否可以像这样获取列表?

  • 1灯
  • 1篇论文
  • 卫生间1
  • 卫生间2
  • 浴室10
  • 卧室1
  • 卧室2
  • 10号卧室

所有列表元素都不包含数字,并且列表长约1500行

我尝试使用此代码,它在包含数字的元素上工作正常,而在仅包含字符串的元素上不起作用:

public class SemiNumericComparer : IComparer<string>
    {
        public int Compare(string s1, string s2)
        {
            if (IsNumeric(s1) && IsNumeric(s2))
            {
                if (Convert.ToInt32(s1) > Convert.ToInt32(s2)) return 1;
                if (Convert.ToInt32(s1) < Convert.ToInt32(s2)) return -1;
                if (Convert.ToInt32(s1) == Convert.ToInt32(s2)) return 0;
            }

            if (IsNumeric(s1) && !IsNumeric(s2))
                return -1;

            if (!IsNumeric(s1) && IsNumeric(s2))
                return 1;

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

        public static bool IsNumeric(object value)
        {
            try
            {
                int i = Convert.ToInt32(value.ToString());
                return true;
            }
            catch (FormatException)
            {
                return false;
            }
        }
    }

3 个答案:

答案 0 :(得分:3)

尝试遵循自定义IComparable:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace ConsoleApplication107
{
    class Program
    {
        static void Main(string[] args)
        {
            List<string> input = new List<string>() { "1 Light", "1 Paper", "Bathroom 1", "Bathroom 2", "Bathroom 10", "Bedroom 1", "Bedroom 2", "Bedroom 10" };

            List<string> results = input.Select(x => new { s = x, order = new Order(x) }).OrderBy(x => x.order).Select(x => x.s).ToList();

        }
    }
    public class Order : IComparable<Order>
    {
        List<string> split { get; set; }

        public Order(string line)
        {
            split = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList();
        }

        public int CompareTo(Order other)
        {

            int min = Math.Min(split.Count, other.split.Count);
            int thisNumber = 0;
            int otherNumber = 0;
            for (int i = 0; i < min; i++)
            {
                if (split[i] != other.split[i])
                {
                    if ((int.TryParse(split[i], out thisNumber)))
                    {
                        if ((int.TryParse(other.split[i], out otherNumber)))
                        {
                            return thisNumber.CompareTo(otherNumber); //both numbers
                        }
                        else
                        {
                            return -1; // this is number other is string : this comes first
                        }
                    }
                    else
                    {
                        if ((int.TryParse(other.split[i], out otherNumber)))
                        {
                            return 1; //other is number this is string : other comes first
                        }
                        else
                        {
                            return split[i].CompareTo(other.split[i]);
                        }
                    }
                }
            }

            return split.Count.CompareTo(other.split.Count);

        }

    }
}

答案 1 :(得分:2)

        [SuppressUnmanagedCodeSecurity]
        internal static class SafeNativeMethods
        {
            [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
            public static extern int StrCmpLogicalW(string p1, string p2);
        }

        public sealed class StringComparer : IComparer<string>
        {
            public int Compare(string a, string b)
            {
                return SafeNativeMethods.StrCmpLogicalW(a, b);
            }
        }

现在您可以在OrderBy上使用 StringComparer 了:

            List<string> str = new List<string>
            {
                "Bedroom 1",
                "Bedroom 2",
                "Bedroom 10",
                "Bathroom 1",
                "Bathroom 2",
                "Bathroom 10",
                "1 Light",
                "1 Paper"
            };
            str = str.OrderBy(x => x, new StringComparer()).ToList();

答案 2 :(得分:1)

您正在寻找一种“自然排序”算法

例如: https://www.codeproject.com/Articles/22517/Natural-Sort-Comparer