英文:
C# Grouping by calculated values isn't working
问题
这个分组为什么没有正确执行?我按星期和月份进行分组,结果是四个而不是三个。
query.GroupBy(datapoint =>
{
var timeDimensionValue = (DateTime)datapoint.Dimensions[TimeDimension];
var keyValues = groupingFunctions.Select(func => func(timeDimensionValue));
return keyValues.ToArray(); // 例如: { "星期一", 15 };
});
数据:
DateTime(2023, 7, 17, 15, 0, 0)
DateTime(2023, 7, 19, 7, 0, 0)
// 相同DateTime(2023, 7, 19, 7, 0, 0)
// 相同DateTime(2023, 7, 21, 11, 30, 0)
英文:
Why isn't this grouping correctly? I'm grouping by day of week and day of month, and I end up with four results, not three.
query.GroupBy(datapoint =>
{
var timeDimensionValue = (DateTime)datapoint.Dimensions[TimeDimension];
var keyValues = groupingFunctions.Select(func => func(timeDimensionValue));
return keyValues.ToArray(); // Ex: { "Monday", 15 };
});
Data:
DateTime(2023, 7, 17, 15, 0, 0)
DateTime(2023, 7, 19, 7, 0, 0)
// same
DateTime(2023, 7, 19, 7, 0, 0)
// same
DateTime(2023, 7, 21, 11, 30, 0)
答案1
得分: 2
使用数组进行分组不是您想要的,因为数组不会覆盖Equals
和GetHashCode
方法。您想要根据数组包含的值进行分组。由于您在评论中提到这个数组实际上是一个IList<object>
并且是动态的,所以可以包含任何内容,您需要一个可以处理这种情况的自定义比较器:
public class ObjectListComparer: IEqualityComparer<IList<object>>
{
public bool Equals(IList<object> x, IList<object> y)
{
if(x == null && y == null) return true;
if(x == null || y == null) return false;
return x.SequenceEqual(y);
}
public int GetHashCode(IList<object> obj)
{
return string.Join(",", obj?.Select(obj => obj) ?? Enumerable.Empty<object>()).GetHashCode();
}
}
现在,您可以在GroupBy
和许多其他LINQ方法中使用这个比较器:
var groups = data.GroupBy(x => {
var timeDimensionValue = (DateTime)datapoint.Dimensions[TimeDimension];
List<object> keyValues = groupingFunctions.Select(func => func(timeDimensionValue));
return keyValues;
}, new ObjectListComparer());
由于这是一个针对IList<object>
的比较器,您可以将其用于您的List<object>
以及object[]
。
英文:
Grouping by an array is not what you want, because arrays don't override Equals
and GetHashCode
. You want to group by the values the array contains. Since you said in a comment that this array is actually a IList<object>
and dynamic, so can contain anything, you need a custom comparer which can handle that:
public class ObjectListComparer: IEqualityComparer<IList<object>>
{
public bool Equals(IList<object> x, IList<object> y)
{
if(x == null && y == null) return true;
if(x == null || y == null) return false;
return x.SequenceEqual(y);
}
public int GetHashCode(IList<object> obj)
{
return string.Join(",", obj?.Select(obj => obj) ?? Enumerable.Empty<object>()).GetHashCode();
}
}
Now you could use this comparer in GroupBy
and many other LINQ methods:
var groups = data.GroupBy(x => {
var timeDimensionValue = (DateTime)datapoint.Dimensions[TimeDimension];
List<object> keyValues = groupingFunctions.Select(func => func(timeDimensionValue));
return keyValues;
}, new ObjectListComparer());
Since it's a comparer for IList<object>
you can use it for your List<object>
but also for object[]
.
答案2
得分: 0
你不能像那样对数组进行分组,因为它们没有基于内容的相等语义,只有基于数组引用的相等性。
你可以使用 HashSet
,还可以使用 HashSetComparer
:
query.GroupBy(datapoint =>
{
var timeDimensionValue = (DateTime)datapoint.Dimensions[TimeDimension];
var keyValues = groupingFunctions.Select(func => func(timeDimensionValue));
return keyValues.ToHashSet(); // 例如: { "Monday", 15 };
}, HashSet<object>.CreateSetComparer());
出于性能原因,你可能希望找到一种存储每个集合的实际哈希码的方法。
英文:
You cannot group by arrays like that, as they have no equality semantics based on their contents, only on array reference.
You can use a HashSet
instead, along with a HashSetComparer
query.GroupBy(datapoint =>
{
var timeDimensionValue = (DateTime)datapoint.Dimensions[TimeDimension];
var keyValues = groupingFunctions.Select(func => func(timeDimensionValue));
return keyValues.ToHashSet(); // Ex: { "Monday", 15 };
}, HashSet<object>.CreateSetComparer());
You may wish to find a way to store the actual hashcode for each set, for performance reasons.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论