.net OrderBy一个包含“厘米”、“米”和“公里”的列表

gstyhher  于 2022-11-19  发布在  .NET
关注(0)|答案(6)|浏览(170)

我有一个List<string>的数组列表,其中包含按以下顺序排列的值["1m", "1cm", "4km","2cm"](厘米、米和公里)
当我想对这个数组进行排序时,我得到了一个错误的答案。我使用了OrderBy:

List<string> data = new List<string> { "1m", "1cm", "4km","2cm" };
var result= data.OrderBy(x => x).ToList();

结果是:

{ "1cm", "1m", "2cm", "4km"}

但我希望答案是这样的顺序--{ "1cm", "2cm", "1m", "4km"}

dgtucam1

dgtucam11#

您已经按字母顺序对数据进行了排序。首先比较first character。然后比较second character和...
您需要基于cm(or m)对数据进行规范化,然后进行排序。

List<string> data = new List<string> { "1m", "1cm", "4km","2cm" };
   var result = data.OrderBy(x => lenghtCM(x));

    public int lenghtCM(string lenghtStr)
    {
        if (lenghtStr.Contains("cm"))
        {
            string num = lenghtStr.Split("cm")[0];
            return int.Parse(num);
           
        } 
        else if (lenghtStr.Contains("km"))
        {
            string num = lenghtStr.Split("km")[0];
            return int.Parse(num) * 100*1000;
        }
        else if (lenghtStr.Contains("m"))
        {
            string num = lenghtStr.Split('m')[0];
            return int.Parse(num) * 100;
        }
        return 0;
    }

result
{“1厘米”、“2厘米”、“1米”、“4公里”}

yk9xbfzb

yk9xbfzb2#

private string[]  normalaizeArray(string[] inputArray)
{
    for (int i= 0 ; i < inputArray.Length; i++)
    {
        if(inputArray[i].Contains('m'))
        {
            inputArray[i] = (float.Parse(inputArray[i].Split('k')[0]) * 100).ToString();
        } else if(inputArray[i].Contains('km'))
        {
            inputArray[i] = (float.Parse(inputArray[i].Split('k')[0]) * 100*1000).ToString();
        }
        else
        {
            inputArray[i] = inputArray[i].Replace("cm", "");
        }
    }
    inputArray = inputArray.OrderBy(x => int.Parse(x)).ToArray();
    for (int i = 0; i < inputArray.Length; i++)
    {
        if(int.Parse(inputArray[i])>1000*100)
            inputArray[i] = (float.Parse(inputArray[i])/1000).ToString() + "km"; 
        else if(int.Parse(inputArray[i])>100)
            inputArray[i] = (float.Parse(inputArray[i])/100).ToString() + "m";
        else
            inputArray[i] = inputArray[i] + 'cm';
    }
    return inputArray;
}
fykwrbwg

fykwrbwg3#

如果可以,请先解析字符串:

enum Unit { cm, m, km }

record Measurment(int Length, Unit Unit)
{
    public override string ToString() => $"{Length}{Enum.GetName(typeof(Unit), Unit)}";

    public double NormalizedLength => Unit switch
    {
        Unit.cm => Length * 0.001,
        Unit.m => Length * 1.0,
        Unit.km => Length * 1000.0,
        _ => throw new NotImplementedException()
    };

    public static Measurment Parse(string source)
    {
        var digits = source.TakeWhile(char.IsDigit).Count();
        var length = int.Parse(source.AsSpan(0, digits));

        // switches with source.AsSpan(digits) in preview
        var measure = source[..digits] switch
        {
            "cm" => Unit.cm,
            "m" => Unit.m,
            "km" => Unit.km,
            _ => throw new NotImplementedException(),
        };
        return new Measurment(length, measure);
    }
}

var result = data.Select(Measurment.Parse).OrderBy(x => x.NormalizedLength).ToList();

这样你就可以按照NormalizedLength对你的测量值进行排序,而ToString会返回原来的字符串。应该很快,很容易扩展新的单位,如果你把Parse转换成TryParse模式,你可以使它具有容错性。

mkshixfv

mkshixfv4#

有一个NuGet包可以管理解析和操作SI单位,称为UnitsNet
如果安装该软件包(通过添加|NuGet Package,搜索并选择UnitsNet并安装它),然后可以编写下面的代码:
(You需要先在代码文件的顶部添加using UnitsNet;
这也适用于nm等。

List<string> data = new List<string> { "1m", "1cm", "4km", "2cm" };

var result = data.OrderBy(Length.Parse).ToList();

Console.WriteLine(string.Join(", ", result));

这将输出"1cm, 2cm, 1m, 4km"

qojgxg4l

qojgxg4l5#

您需要使用IComparable自定义排序

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

namespace ConsoleApplication49
{
    
    class Program
    {
        static void Main(string[] args)
        {
            List<string> data = new List<string> { "1m", "1cm", "4km", "2cm" };
            List<string> results = data.Select(x => new SortDistance(x)).OrderBy(x => x).Select(x => x.value).ToList();

        }
    }
    public class SortDistance : IComparable<SortDistance>
    {
        const string pattern = @"(?'number'\d+)(?'multiplier'.*)";
        List<string> distanceOrder = new List<string>() { "cm", "m", "km" };
        public string value { get; set; }
        public int distance { get; set; }
        public string multiplier { get; set; }

        public SortDistance(string value)
        {
            this.value = value;
            Match match = Regex.Match(value, pattern);
            this.distance = int.Parse(match.Groups["number"].Value);
            this.multiplier = match.Groups["multiplier"].Value;
        }
        public int CompareTo(SortDistance other)
        {
            if (this.multiplier == other.multiplier)
                return this.distance.CompareTo(other.distance);
            else
                return distanceOrder.IndexOf(this.multiplier).CompareTo(distanceOrder.IndexOf(other.multiplier));
        }
    }
}
fkvaft9z

fkvaft9z6#

不能使用OrderBy进行排序。
您必须首先定义从所有单位到最小单位的转换。例如,m到cm,km到cm.....
所以1m等于100 cm
那么你必须遍历你的列表,检查每一项的单位,得到它的最小单位。
创建另一个列表。
您可以实现插入排序来对项进行排序并添加基于比较的保持插入项。

相关问题