以与第一个列表相同的顺序对对象列表中的多个列表进行排序



我有这个包含两个字符串列表的对象列表,这两个字符串是链接的,我想对两个列表进行排序valeursProductUid取决于价值的顺序。

列表产品:

[
{
"groupBy": "coloris",
"valeurs": [
"Beige",
"Gris clair",
"Anthracite",
"Beige",
"Augusta",
"Venezia"
],
"ProductUid": [
"TEST1",
"TEST2",
"TEST3",
"TEST4",
"TEST5",
"TEST6"
]
},
{
"groupBy": "ref_commercial",
"valeurs": [
"29245",
"51625",
"25269",
"29245",
"72585",
"72584"
],
"ProductUid": [
"TEST1",
"TEST2",
"TEST3",
"TEST4",
"TEST5",
"TEST6"
]
}
]

所以最终的结果会是这样的。

排序结果:

[
{
"groupBy": "coloris",
"valeurs": [
"Anthracite",
"Augusta",
"Beige",
"Beige",
"Gris clair",
"Venezia"
],
"ProductUid": [
"TEST3",
"TEST5",
"TEST1",
"TEST4",
"TEST2",
"TEST6"
]
},
{
"groupBy": "ref_commercial",
"valeurs": [
"25269",
"29245",
"29245",
"51625",
"72584",
"72585"
],
"ProductUid": [
"TEST3",
"TEST1",
"TEST4",
"TEST2",
"TEST6"
"TEST5",
]
}
]

我已经做的是

创建列表产品时

var result = lProd.SelectMany(x => x.Caracteristiques.Distinct(), (parentObj, childnum) =>
new
{
parentObj,
childnum
})
.GroupBy(x => x.childnum.nom)
.Select(x => new 
{
groupBy = x.Key,
valeurs = x.Select(z => z.childnum.valeur).OrderBy(q => q), // Sort List Valeurs
ProductUid = x.Select(z => z.parentObj.ProductUid), // Want to do the same sort here
}).Where(sid => OrdredList.Any(si => si == sid.groupBy))
.OrderBy(x => OrdredList.IndexOf(x.groupBy));

我能够对valeurs列表进行排序,但找不到在产品UID上使用相同的排序的方法,

有没有办法做到这一点?

为了使您的任务更容易,我建议您将对象的结构更改为元组(属性,uid)。即使您不需要排序,我也建议您这样做。

.Select(x => new 
{
groupBy = x.Key,
valeursAndUids = x
.Select(z => (Valeur: z.childnum.valeur, Uid: z.parentObj.ProductUid))
.OrderBy(q => q.Valeur)
}

您可以创建一个索引列表,并通过在第一个列表中查找值来对其进行排序,然后使用索引从第二个列表中选择值。假设列表长度相等:

var l1 = new[] {1, 0, 2, 3};
var l2 = new[] {"b", "a", "c", "d"};
var indices = new int[l1.Length];
for (int i = 0; i < indices.Length; i++)
{
indices[i] = i;
}
var sortedIndices = indices.OrderBy(i => l1[i]).ToList();
var l2Sorted = sortedIndices.Select(i => l2[i]).ToList();
var l1Sorted = sortedIndices.Select(i => l1[i]).ToList();
Console.WriteLine(string.Join(", ", l2Sorted));

此程序生成所需的输出:

var json = File.ReadAllText("data.json");
var list = JsonSerializer.Deserialize<List<X>>(json);
foreach(var x in list)
{
var combined = x.valeurs.Zip( x.ProductUid, (valuer, uid) => (valuer, uid) );
var sorted = combined.OrderBy(p => p.valuer);
x.valeurs = sorted.Select( p => p.valuer).ToList();
x.ProductUid = sorted.Select( p => p.uid).ToList();
// Or 
// var combined = x.valeurs.Zip(x.ProductUid);
// var sorted = combined.OrderBy(p => p.First);
// x.valeurs = sorted.Select( p => p.First).ToList();
// x.ProductUid = sorted.Select( p => p.Second).ToList();
}

Console.WriteLine(JsonSerializer.Serialize(list, new JsonSerializerOptions()
{
WriteIndented = true
}));
class X {
public List<string> valeurs {get; set; }
public List<string> ProductUid {get; set; }
}

这是一个相对简单的方法来实现这一点:

var x = j.Select(e => {
var map = e.Valeurs.Select((v, i) => (v, i)).OrderBy(t => t.v).Select(t => t.i).ToArray();
return new SomeNamespace.SomeRoot
{
GroupBy = e.GroupBy,
Valeurs = map.Select(i => e.Valeurs[i]).ToArray(),
ProductUid = map.Select(i => e.ProductUid[i]).ToArray(),
};
}
);

j是原始 JSON 的对象表示形式。我将在答案末尾给出解析它的类。本质上j是一个2长SomeRoot数组,一个具有string GroupBystring[] Valuersstring[] ProjectUids性质的对象。它表示根 json 数组中的对象

我们做的第一件事,在这一行:

var map = e.Valeurs.Select((v, i) => (v, i)).OrderBy(t => t.v).Select(t => t.i).ToArray();

是,对于每个根对象,将e.Valuers投影到一个元组,该元组包含找到该值的索引,i。然后我们按值排序v;这意味着我们有一个排序数组,它记住原始元素的找到位置:Anthracite位于索引2但在排序后,数组的第一个元素为(Anthracite, 2)元组。整个数组如下所示:

[
(Anthracite, 2),      <-- now in slot 0 but remembers it used to be in slot 2
(August, 4),
(Beige, 0),
(Beige, 3),
(Gris clair, 1)
(Venezia, 5)
]

这种"对它在哪里的记忆"将在以后有用。我们接下来要做的是扔掉Anthracite等,只保留2

这意味着map是一个整数数组,运行方式类似于[2,4,0,3,1,5]

如果您按此顺序(2,4,0,3,1,5)访问原始评估器数组,则按顺序获得颜色,无烟煤色,八月色,米色,米色。

..因此,您还可以使用相同的映射数组来访问ProjectUids,以相同的顺序获取它们,2,4,0,3,1,5

因此,您的新评估器和ProjectUid数组将变为:

Valeurs = map.Select(i => e.Valeurs[i]).ToArray(),
ProductUid = map.Select(i => e.ProductUid[i]).ToArray(),

你可以把它想象成 *,因为map[0] == 2原始数组中索引 2 中的内容现在位于排序数组的索引 0 中。地图数组本质上映射了"它需要的位置:它实际在哪里">


要更改排序依据,请更改.OrderBy(t => t.v)-tv元组,原始评估器值和i,找到它的索引。


以下是从 JSON 到要求的完整代码,包括用于解析 json 的类:

//impl
var s = 
@"[
{
""groupBy"": ""coloris"",
""valeurs"": [
""Beige"",
""Gris clair"",
""Anthracite"",
""Beige"",
""Augusta"",
""Venezia""
],
""ProductUid"": [
""TEST1"",
""TEST2"",
""TEST3"",
""TEST4"",
""TEST5"",
""TEST6""
]
},
{
""groupBy"": ""ref_commercial"",
""valeurs"": [
""29245"",
""51625"",
""25269"",
""29245"",
""72585"",
""72584""
],
""ProductUid"": [
""TEST1"",
""TEST2"",
""TEST3"",
""TEST4"",
""TEST5"",
""TEST6""
]
}
]";
var j = SomeNamespace.SomeRoot.FromJson(s);
var x =  j.Select(e => {
var map = e.Valeurs.Select((v, i) => (v, i)).OrderBy(t => t.v).Select(t => t.i).ToArray();
return new SomeNamespace.SomeRoot
{
GroupBy = e.GroupBy,
Valeurs = map.Select(i => e.Valeurs[i]).ToArray(),
ProductUid = map.Select(i => e.ProductUid[i]).ToArray(),
};
}
);


//parsing classes
namespace SomeNamespace
{
using System;
using System.Collections.Generic;
using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
public partial class SomeRoot
{
[JsonProperty("groupBy")]
public string GroupBy { get; set; }
[JsonProperty("valeurs")]
public string[] Valeurs { get; set; }
[JsonProperty("ProductUid")]
public string[] ProductUid { get; set; }
}
public partial class SomeRoot
{
public static SomeRoot[] FromJson(string json) => JsonConvert.DeserializeObject<SomeRoot[]>(json, SomeNamespace.Converter.Settings);
}
public static class Serialize
{
public static string ToJson(this SomeRoot[] self) => JsonConvert.SerializeObject(self, SomeNamespace.Converter.Settings);
}
internal static class Converter
{
public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
{
MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
DateParseHandling = DateParseHandling.None,
Converters =
{
new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
},
};
}
}

最新更新