C# 顺序字符串式数字

C# 顺序字符串式数字,c#,linq,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行长 我尝试过使用这段代码,它在包含n

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

我的清单如下:

  • 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行长

我尝试过使用这段代码,它在包含number的元素上运行良好,但不仅仅在字符串元素上运行:

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;
            }
        }
    }
公共类SemiNumericComparer:IComparer
{
公共整数比较(字符串s1、字符串s2)
{
if(IsNumeric(s1)和&IsNumeric(s2))
{
if(Convert.ToInt32(s1)>Convert.ToInt32(s2))返回1;
if(Convert.ToInt32(s1)
您正在寻找一种“自然排序”算法

例如:

尝试以下自定义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);

        }

    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.IO;
命名空间控制台应用程序107
{
班级计划
{
静态void Main(字符串[]参数)
{
列表输入=新列表(){“1灯”、“1纸”、“浴室1”、“浴室2”、“浴室10”、“卧室1”、“卧室2”、“卧室10”};
List results=input.Select(x=>new{s=x,order=neworder(x)}).OrderBy(x=>x.order).Select(x=>x.s).ToList();
}
}
公共类秩序:IComparable
{
列表拆分{get;set;}
公共秩序(字符串行)
{
split=line.split(新字符[]{''},StringSplitOptions.removeMptyEntries.ToList();
}
公共整数比较(订购其他)
{
int min=Math.min(split.Count,other.split.Count);
int thisNumber=0;
int otherNumber=0;
对于(int i=0;i
您希望“2灯”和“10灯”的效果如何?“浴室蓝”怎么样?我不确定这是否适合您,但您可以编辑字符串,使其具有前导零<代码>浴室001
浴室002
,等等。或者,在运行时将数字部分转换为该格式,然后进行排序。两者在“边缘案例”场景中的工作方式应该有所不同。如果您有问题,请在您的数据上尝试一个,具体到案例中。但我很确定,如果它不是一个完全任意的规则,那么它要么是一个复制,要么是一个内置函数。自从我们开始使用计算机以来,人类一直在要求按顺序排列物品清单。我希望开发人员能在第二天找到一个简单的解决方案。这只适用于Windows环境。此外,如果可以(轻松地)避免引用内核dll,我也不建议引用它。除了@discy提到的内容之外,值得注意的是,strmplogical在不同的Windows版本上的行为可能会有所不同(这可能是可取的,也可能不是可取的,这取决于排序是否应与运行程序的Windows版本的排序行为相匹配)。
            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();
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);

        }

    }
}