[英]Linq OrderBy to group objects with the same sets
I have a set of objects that themselves contain a set. 我有一组自己包含一组的对象。
private class Pilot
{
public string Name;
public HashSet<string> Skills;
}
Here's some test data: 这是一些测试数据:
public void TestSetComparison()
{
var pilots = new[]
{
new Pilot { Name = "Smith", Skills = new HashSet<string>(new[] { "B-52", "F-14" }) },
new Pilot { Name = "Higgins", Skills = new HashSet<string>(new[] { "Concorde", "F-14" }) },
new Pilot { Name = "Jones", Skills = new HashSet<string>(new[] { "F-14", "B-52" }) },
new Pilot { Name = "Wilson", Skills = new HashSet<string>(new[] { "F-14", "Concorde" }) },
new Pilot { Name = "Celko", Skills = new HashSet<string>(new[] { "Piper Cub" }) },
};
I want to use OrderBy
in Linq so that: 我想在Linq中使用
OrderBy
,以便:
I think I need to implement an IComparer<Pilot>
to pass into OrderBy
but don't know how to handle the "doesn't matter" aspect (above) and the stable sort. 我想我需要实现一个
IComparer<Pilot>
来传递给OrderBy
但不知道如何处理“无关紧要”方面(上面)和稳定排序。
UPDATE: 更新:
I want the output to be an array of the same five Pilot
objects but in a different order . 我希望输出是相同的五个
Pilot
对象的数组 ,但顺序不同 。
When GroupBy
you have to implement IEqualityComparer<T>
for the type you are going to group ( HashSet<string>
in your case), eg 当
GroupBy
你必须为要分组的类型(在你的情况下为HashSet<string>
)实现IEqualityComparer<T>
,例如
private sealed class MyComparer : IEqualityComparer<HashSet<string>> {
public bool Equals(HashSet<string> x, HashSet<string> y) {
if (object.ReferenceEquals(x, y))
return true;
else if (null == x || null == y)
return false;
return x.SetEquals(y);
}
public int GetHashCode(HashSet<string> obj) {
return obj == null ? -1 : obj.Count;
}
}
And then use it: 然后使用它:
IEnumerable<Pilot> result = pilots
.GroupBy(pilot => pilot.Skills, new MyComparer())
.Select(chunk => string.Join(", ", chunk
.Select(item => item.Name)
.OrderBy(name => name))); // drop OrderBy if you want stable Smith, Jones
Console.WriteLine(string.Join(Environment.NewLine, result));
Outcome: 结果:
Jones, Smith
Higgins, Wilson
Celko
Edit: If you want an array reodered then add SelectMany()
in order to flatten the groupings and the final ToArray()
: 编辑:如果要重新编码数组,请添加
SelectMany()
以展平分组和最终的ToArray()
:
var result = pilots
.GroupBy(pilot => pilot.Skills, new MyComparer())
.SelectMany(chunk => chunk)
.ToArray();
Console.WriteLine(string.Join(", ", result.Select(p => p.Name)));
Outcome: 结果:
Jones, Smith,
Higgins, Wilson,
Celko
Note that string.join combines the names of each group in one line, ie Jones, Smith
both have the same skill set. 请注意,string.join将每个组的名称组合在一行中,即
Jones, Smith
都具有相同的技能组合。
Run it as DotNetFiddle 将其作为DotNetFiddle运行
You can use the following implementation of HashSetByItemsComparer to accomplish what you need: 您可以使用HashSetByItemsComparer的以下实现来完成您的需要:
public class HashSetByItemsComparer<TItem> : IComparer<HashSet<TItem>>
{
private readonly IComparer<TItem> _itemComparer;
public HashSetByItemsComparer(IComparer<TItem> itemComparer)
{
_itemComparer = itemComparer;
}
public int Compare(HashSet<TItem> x, HashSet<TItem> y)
{
foreach (var orderedItemPair in Enumerable.Zip(
x.OrderBy(item => item, _itemComparer),
y.OrderBy(item => item, _itemComparer),
(a, b) => (a, b))) //C# 7 syntax used - Tuples
{
var itemCompareResult = _itemComparer.Compare(orderedItemPair.a, orderedItemPair.b);
if (itemCompareResult != 0)
{
return itemCompareResult;
}
}
return 0;
}
}
It is not the most efficient solution probably, since it orders hashsets for each comparison separately. 它可能不是最有效的解决方案,因为它分别为每个比较命令哈希集。 You may need to optimize it if using with millions of pilots and many skills, but for small numbers it will work just fine.
如果使用数百万的飞行员和许多技能,您可能需要对其进行优化,但对于小数字,它可以正常工作。
Usage example: 用法示例:
var sortedPilots = pilots.OrderBy(p => p.Skills, new HashSetByItemsComparer<string>(StringComparer.Ordinal));
foreach (var pilot in sortedPilots)
{
Console.WriteLine(pilot.Name);
}
And output is: 输出是:
Smith
Jones
Higgins
Wilson
Celko
So it preserves equal items ordering (default behavior of OrderBy
- you don't need to worry about it). 因此它保留了相同的项目排序 (
OrderBy
默认行为 - 您不必担心它)。 By the way, solution with GroupBy
would not allow you to restore items order as far as I know. 顺便说一下,就我所知,
GroupBy
解决方案不允许你恢复项目顺序。
Here is a sample with orderby 这是一个带有orderby的示例
var groups = from c in GridImage (Your List)
orderby c.grouping (Your Item inside List)
group c by c.grouping;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.