【问题标题】:OrderBy numbers that are strings (cannot convert to int)作为字符串的 OrderBy 数字(无法转换为 int)
【发布时间】:2015-08-25 15:31:33
【问题描述】:

我正在尝试对包含元素列表的List<string> 进行排序,其中每个元素都是数字后跟字母。这就是为什么不能简单地将每个元素转换为 int 的原因。该列表在运行时生成,但例如,该列表可能包含以下元素:

10 dog, 53 cow, 2 crow, 29 horse, 12 rabbit, 107 frog, 35 cat, 7 dragon

我试过这样排序:

public void Compare()
{   
   sortedList = sortedList.OrderBy(g => g).ToList(); 
}

结果:

10 dog, 107 frog, 12 rabbit, 2 crow, 29 horse, 35 cat, 53 cow, 7 dragon

显然它是按字母顺序排序的,因为在这个例子中,107 排在 12 之前,而 107 中的“10”小于 12。但我需要以某种方式对其进行排序,使其按单词前面的数字顺序返回.

我需要这个例子来返回:

2 crow, 7 dragon, 10 dog, 12 rabbit, 29 horse, 35 cat, 53 cow, 107 frog

我对编码很陌生,这让我完全难过。关于如何实现我想要的结果的任何建议?

【问题讨论】:

  • 您需要将数字与单词分开以进行排序。这个词总是一个词吗?如果是这样,您可以按空格分割字符串。但是,如果您可以有多个单词,则需要找到一种可靠地拆分它的方法。
  • 虽然这是一个简化的示例,需要简化的解决方案,但您要寻找的通常称为“自然排序”。现有的解决方案可以解决这个问题,还可以处理字符串中不同数量的数字、不同的位置等问题。
  • @lbanezowns ,您应该考虑将有效的答案标记为已接受。

标签: c# .net string linq list


【解决方案1】:

你可以提取你想要的数据,然后按顺序进行排序

var sorted = list
    .Select(x => new
    {
        Splited = x.Split(),
        Raw = x
    }) //split the string and keep the raw value
    .Select(x => new
    {
        Count = int.Parse(x.Splited[0]), // extract the number 
        Raw = x.Raw
    })
    .OrderBy(x => x.Count) //order by that number
    .Select(x => x.Raw); //select raw value

【讨论】:

  • 如果 OP 需要对原始列表进行排序,他应该调用 ToList 并将其分配给原始列表变量。
  • 工作就像一个魅力!非常感谢!
【解决方案2】:

正如您已经确定的那样,问题是您不能OrderBy 字符串。您想对列表中的数字部分进行排序,将其视为数字。

我们将告诉OrderBy 对该部分进行排序,方法是在第一个空格处拆分字符串,将第一部分parts[0] 转换为int 并根据该值对列表进行排序。

无需使用Select,存储原始值等。只是在原来的List 上加上一个简单的OrderBy

namespace SortListTest1
{
    using System;
    using System.Collections.Generic;
    using System.Linq;

    class Program
    {
        static void Main(string[] args)
        {
            var animals = new List<string> { "10 dog", "53 cow", "2 crow", "29 horse", "12 rabbit", "107 frog", "35 cat", "7 dragon" };

            var orderedAnimals = animals.OrderBy(
                x =>
                    {
                        var parts = x.Split(' '); // split on first space
                        return int.Parse(parts[0]); // i.e. the numeric part, cast to an int
                    });

            foreach (var orderedAnimal in orderedAnimals)
            {
                Console.WriteLine(orderedAnimal);
            }
        }
    }
}

2 crow
7 dragon
10 dog
12 rabbit
29 horse
35 cat
53 cow
107 frog
Press any key to continue . . .

【讨论】:

    【解决方案3】:

    使用这些行进行排序:

    List<string> L = new List<string> { "10 dog", "53 cow", "2 crow", "29 horse", "12 rabbit", "107 frog", "35 cat", "7 dragon" };
    
    var sort = from s in L
               orderby Convert.ToInt32(s.Split(' ')[0]) 
               select s;
    

    【讨论】:

      【解决方案4】:

      我建议不要使用字符串列表,而是使用字典。您的数据结构看起来像是键值形式。

      Dictionary<int,string> Animals = new Dictionary<int,string>();
      

      让关键部分取整数部分,让字符串部分处理名称部分。

      然后你可以很容易地对数据结构进行如下排序

      sortedAnimalList = Animals.OrderByAscending(a => a.Key);
      

      【讨论】:

        【解决方案5】:

        使用空格作为分隔符拆分字符串,取第一个值并转换为int

        sortedList = sortedList
            .OrderBy(g => Int32.Parse(g.Split(' ')[0]))
            .ToList()
        

        【讨论】:

          【解决方案6】:

          我建议采取不同的方法:您有一个 (count, name) 对(或 (id, name) 对)的列表,其中name 是您的数据对象,@987654327 @ 一个量词。

          1. 解析数据以将其拆分为原子值(在本例中为 intstring
          2. 将值放入适合您需要的指定结构中(这里只是属性name)。
          3. 在适当的容器类中组装数据对象(如List`1Dictionary`2
          4. 如果没有排序,就排序;您可能需要让您的数据结构/类实现IComparable`1/IComparable 或定义自定义IComparer`1


          这是我想出的:

          代码:

          static void Main(string[] args) {
              var unsortedList = new List<string>() { "10 dog", "53 cow", "2 crow", "29 horse", "12 rabbit", "107 frog", "35 cat", "7 dragon" };
              var sortedList = new SortedList<int, string>((int)unsortedList.Count);
              foreach(var entry in unsortedList) {
                  string[] frags = entry.Split(' ');
                  if(frags.Length != 2) {
                      throw new FormatException();
                  }
                  int count = Convert.ToInt32(frags[0]);
                  string name = frags[1];
                  sortedList.Add(count, name);
              }
              Console.WriteLine("UNSORTED:");
              unsortedList.ForEach(Console.WriteLine);
              Console.WriteLine();
          
              Console.WriteLine("SORTED:");
              foreach(var entry in sortedList) {
                  Console.WriteLine(entry.Key + " " + entry.Value);
              }
              Console.WriteLine();
              Console.ReadKey();
          }
          

          输出:

          【讨论】:

            【解决方案7】:
            lst = lst.OrderBy(x => Convert.ToInt32(x.Split()[0])).ToList();
            

            【讨论】:

            • 我猜这个也是给的... ;)
            【解决方案8】:

            我知道这不是你要求的。我还看到有很多答案可以完全按照您的要求进行。 这是一个建议

            我不知道你的系统或任何东西,但我认为在这里将你的对象作为字符串处理是一个错误。我很确定您的系统可以受益于拥有和对象,而不是这个代表您的对象的字符串。通过创建一个简单的对象,甚至像

            public class Animal
            {
                public string Name{ get; set }
                public int Index{ get; set; }
            }
            

            您将在许多地方获得类型安全。修改会变得更容易(在您当前的系统中尝试添加第三个属性,例如 Type [“Mammal”、“Reptile”、“Fish”等],您会明白我在说什么)。如果您需要将该对象显示为您拥有的字符串,您可以随时覆盖该对象的ToString(),例如描述的here

            public override string ToString() 
            {
                return string.Format("{0} {1}", Index, Name);
            }
            

            现在,当您需要订购或对对象进行任何操作时,它会变得更加简单,因为您有一个常规对象,而不是包含对象的字符串。

            【讨论】:

              【解决方案9】:

              试试这个

              sortedList.OrderBy(g => int.Parse(g.Split(' ').First())).ToList();
              

              【讨论】:

                猜你喜欢
                • 2018-05-10
                • 2020-08-10
                • 2012-05-28
                • 1970-01-01
                • 2020-12-12
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多