将字符串分割为数组并对数组进行排序

5
我正在尝试对逗号分隔的字符串进行排序。但是它并没有按照我的期望表现。
var classes = "10,7,8,9";
Console.Write(string.Join(",", classes.Split(',').OrderBy(x => x)));
Console.ReadKey();

输出结果为

10,7,8,9

但我希望期望的输出结果是:

7,8,9,10

班级可以有一个附加的部分,比如7a、7b

我希望只用一行代码就能实现它。


我知道这可能根本不是一个解决方案,但你不能重新排列 var classes,使它们在拆分之前按正确顺序出现吗?如果您读取动态数据,可以在该查询上执行排序操作,这样做是否可行? - Xariez
首先将数组的每个元素转换为整数,然后尝试排序。 - SPnL
为什么必须在一行代码中实现? - swatsonpicken
@swatsonpicken 因为我正在将多个对象绑定到列表中,而这个字符串是每个对象的属性。 - Imran Ahmad Shahid
创建一个包含intchar(或string)的结构体,编写一个从一个字符串项到该结构体的解析方法,使用确切的比较逻辑(首先是int部分,然后是char/string部分)创建一个IComparer<YourStruct>,并在OrderBy中使用它。 - Corak
显示剩余2条评论
6个回答

3
您可以像这样使用正则表达式
var classes = "10,7,8,9";
Regex number = new Regex(@"^\d+");
Console.Write(string.Join(",", classes.Split(',').OrderBy(x => Convert.ToInt32(number.Match(x).Value)).ThenBy(x => number.Replace(x, ""))));
Console.ReadKey();

正如我所提到的,类别可以带有一个章节,例如7a、7b。 - Imran Ahmad Shahid
这里的数字是什么? - tabby
1
@tabby忘记写了!现在已经修复。 - Kahbazi

1

代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Collections;
namespace Rextester
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var l = new List<string> { "1D", "25B", "30A", "9C" };
    l.Sort((b, a) =>
    {
        var x = int.Parse(Regex.Replace(a, "[^0-9]", ""));
        var y = int.Parse(Regex.Replace(b, "[^0-9]", ""));
        if (x != y) return y - x;
        return -1 * string.Compare(a, b);
    });

    foreach (var item in l) Console.WriteLine(item);

        }
    }
}

输出: 1D 9C 25B 30A

在线编译: http://rextester.com/CKKQK66159


我已经编写了一个函数,可以调用它,输入字符串,返回排序后的字符串。 - Imran Ahmad Shahid

1
使用以下的using指令:
using System.Text.RegularExpressions;

尝试以下内容:
var input = "7,7a,8,9a,9c,9d,10";
var sorted = from sp in input.Split(',')
             let reg = Regex.Match(sp, @"(?<num>[0-9]+)(?<char>[a-z]*)", RegexOptions.IgnoreCase | RegexOptions.Compiled)
             let number = int.Parse(reg.Groups["num"].ToString())
             orderby reg.Groups["char"].ToString() ascending // sort first by letter
             orderby number ascending // then by number
             select sp;
var result = string.Join(",", sorted);

Console.WriteLine(result);
//output (tested): 7,7a,8,9a,9c,9d,10

它使用正则表达式来确定输入字符串的数字和字母部分。 正则表达式模式使用命名组,其格式如下:(?<group_name> regex_expr )
如果您担心大量数字的情况,则上述代码的时间复杂度为O(n log(n))


有关命名Regex组的更多信息。
有关LINQ的更多信息。
...以及关于 orderby 子句的信息。


它很复杂,但也解决了我的问题,谢谢 :) - Imran Ahmad Shahid
可以进一步减少代码复杂度,但我认为这已经足够了。很高兴听到它对你有帮助。 - unknown6656

0

你正在对字符串进行排序(按字母顺序),所以是的,“10”在“7”之前。

我的解决方案将“10,7b,8,7a,9b”转换为“7a,7b,8,9b,10”(首先按整数前缀排序,然后按子字符串本身排序)。

解析字符串前缀的辅助方法:

private static int IntPrefix(string s)
    => s
    .TakeWhile(ch => ch >= '0' && ch <= '9')
    .Aggregate(0, (a, c) => 10 * a + (c - '0'));

按整数前缀排序子字符串,然后按字符串本身排序:

classes.Split(',') // string[]
.Select(s => new { s, i = IntPrefix(s) }) // IEnumerable<{ s: string, i: int }>
.OrderBy(si => si.i) // IEnumerable<{ s: string, i: int }>
.ThenBy(si => si.s) // IEnumerable<{ s: string, i: int }>
.Select(si => si.s) // IEnumerable<string>

一行代码(使用 string.Join):
var result = string.Join(",", classes.Split(',').Select(s => new {s, i =  IntPrefix(s)}).OrderBy(si => si.i).ThenBy(si => si.s).Select(si => si.s));

0

这是我的实现:

IEnumerable<Tuple<string, string[]>> splittedItems =
    items.Select(i => new Tuple<string, string[]>(i, Regex.Split(i, "([0-9]+)")));

List<string> orderedItems = splittedItems.OrderBy(t => Convert.ToInt16(t.Item2[1]))
    .ThenBy(t => t.Item2.Length > 1 ? t.Item2[2] : "1")
    .Select(t => t.Item1).ToList();
  1. 将输入分为数字和非数字字符
  2. 将分割后的字符串与其父字符串一起存储
  3. 按数字排序
  4. 然后按非数字字符排序
  5. 在排序后再次获取父字符串

结果如下所示:{ "10", "7", "8b", "8a", "9" } 排序后为 { "7", "8a", "8b", "9", "10" }


0

所有内容都在一行,还支持“4a”等。

编辑:在测试中,像1,2,111,3这样的字符串会显示为111,1,2,3,所以可能不完全符合您的要求。

        string str = "1,2,3,4a,4b,5,6,4c";
        str.Split(',').OrderBy(x => x).ToList().ForEach(x=> Console.WriteLine(x));
        Console.ReadKey();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接