按名称排序,然后按某些布尔关系分组?(.NET)
本文关键字:NET 关系 排序 然后 布尔 | 更新日期: 2023-09-27 18:32:26
我有一个命名对象列表:
class NamedObject {
public string name;
public int value;
public NamedObject(string name, int value) {
this.name = name;
this.value = value;
}
}
...
public static bool HasRelationship(NamedObject a, NamedObject b) {
return a.value == b.value;
}
...
var objs = new List<NamedObject>();
objs.Add(new NamedObject("D", 1));
objs.Add(new NamedObject("Z", 2));
objs.Add(new NamedObject("Y", 3));
objs.Add(new NamedObject("A", 2));
objs.Add(new NamedObject("C", 1));
objs.Add(new NamedObject("Z", 1));
我想按名称排序,然后按布尔关系进行子排序。在本例中,布尔关系a.value == b.value
。
输出列表:
- 一 (2)
- Z (2)
- C (1)
- D (1)
- Z (1)
- Y (3)
布尔关系分组,按名称对子组进行排序。
编辑:
以上是对实际排序的简化,在我的应用程序中,HasRelationship
函数确定两个方向是否对称。方向被命名,以便它们在编辑器界面中按逻辑顺序显示。
下面是一个可视化:
http://pbrd.co/16okFxp
我对这个问题感到困惑,我会尽量说清楚。
首先,您似乎要按名称对命名对象进行排序,这是清晰易懂的部分。订单应该完成工作。
然后,您希望通过基于一对命名对象的任意谓词来分割它。我认为这就是引起混乱的问题。
您提供的谓词决定了 NamedObject 对的属性,因此现在您正在处理对。这个问题没有唯一的答案。
我知道你想按谓词划分对,但你必须明白,使用布尔分区,你只会有两个分区(关系是否为真),并且分区内没有保证值的顺序。
所以你最多可以得到(在对的第一个术语上按名称排序):
- 对(A,Z)(真)
- 对(A,C)(假)
- 对(A,D)(假)
- 。
- 对(C,D)(真)
- 。
关键是你不能在不隐式处理对的情况下按对关系排序。所以为了给你一个答案,我会假设:
- 关系可能不对称
- 要按第一对术语名称排序
在这种情况下,答案可能是。首先获得配对。
var namedPairs = namedObjects.SelectMany(outerNamedObject =>
namedObjects.Select(innerNamedObject => new
{
First = outerNamedObject,
Second = innerNamedObject
}));
然后我们进行分组
var partitionedNamedPairs = namedPairs.GroupBy(pair =>
HasRelationship(pair.First, pair.Second));
之后,按第一个术语名称排序,然后按组键排序(关系分区)
var result = partitionedNamedPairs.SelectMany(
grouping => grouping.Select(pair => new { pair, key = grouping.Key }))
.OrderBy(keyedPair => keyedPair.pair.First.name)
.ThenBy(keyedPair => keyedPair.key);
然后,您可以使用 select 删除该对的第二项,但我看不出这有什么意义,因为您提供的谓词是二进制的。
我认为你应该单独加入你的列表,因为你的 HasRelationship 方法需要两个对象。
var result = objs.OrderBy(x => x.name)
.Join(objs, _ => true, _ => true, (l, r) => new { l, r, rel = HasRelationship(l, r) })
.Where(x => x.rel)
.SelectMany(x=>new []{x.l,x.r})
.Distinct()
.ToList();
虽然这会返回您期望的列表,但我不能说我清楚地了解您的要求。
以下解决方案已完全注释,希望能帮助此问题的未来读者了解所需的排序过程。
@QtX的回答很好,很简洁,尽管人们似乎很难理解我实际要求的内容,但对不起那些家伙!
使用示例:
var sortedObjs = objs.SortAndGroupByRelationship(obj => obj.name, HasRelationship);
排序和分组的扩展方法:
public static IEnumerable<T> SortAndGroupByRelationship<T, TKey>(this IEnumerable<T> objs, Func<T, TKey> keySelector, Func<T, T, bool> relationship) where TKey : IComparable<TKey> {
// Group items which are related.
var groups = new List<List<T>>();
foreach (var obj in objs) {
bool grouped = false;
// Attempt to place named object into an existing group.
foreach (var group in groups)
if (relationship(obj, group[0])) {
group.Add(obj);
grouped = true;
break;
}
// Create new group for named object.
if (!grouped) {
var newGroup = new List<T>();
newGroup.Add(obj);
groups.Add(newGroup);
}
}
// Sort objects within each group by name.
foreach (var group in groups)
group.Sort( (a, b) => keySelector(a).CompareTo(keySelector(b)) );
// Sort groups by name.
groups.Sort( (a, b) => keySelector(a[0]).CompareTo(keySelector(b[0])) );
// Flatten groups into resulting array.
var sortedList = new List<T>();
foreach (var group in groups)
sortedList.AddRange(group);
return sortedList;
}
var sorted = objs.GroupBy(x => x.value, (k, g) => g.OrderBy(x => x.name))
.OrderBy(g => g.First().name)
.SelectMany(g => g);
准确返回所需的内容,而不使用HasRelationship
方法。