LINQ 中的维恩图样式分组
本文关键字:样式 LINQ | 更新日期: 2023-09-27 18:36:37
Ok.标题可能有点令人困惑,但这是我正在尝试做的
我有一系列自然数
var series = Enumerable.Range(1, 100)
现在我想用GroupBy
把数字分成这3组,素数,偶数,奇数
series.Select(number => {
var type = "";
if (MyStaticMethods.IsPrime(number))
{
Type = "prime";
}
else if (number % 2 == 0)
{
type = "Even";
}
else
{
type = "Odd";
}
return new { Type=type, Number = number };
}).GroupBy(n => n.Type);
现在,上面的查询将错过将偶数或奇数的素数分类为两个类别,它们将只属于"素数"组。上面的选择有什么方法可以产生多个数字吗?
我可以尝试如下方法,但它需要对序列进行额外的扁平化。
series.Select(number => {
var list = new List<int>();
if (MyStaticMethods.IsPrime(number))
{
list.Add(new { Type="prime", Number = number });
}
if (number % 2 == 0)
{
list.Add(new { Type="even", Number = number });
}
else
{
list.Add(new { Type="odd", Number = number });
}
return list;
})
.SelectMany(n => n)
.GroupBy(n => n.Type);
上面的代码解决了我的问题,有没有更好的方法可以使我的代码看起来更"实用"?
您可以在此处使用 linq,但您需要复制一些可以存在于不同组中的值。 GroupBy
仅适用于不相交的群,因此您需要一种方法来区分偶数2
并2
素数。 你所做的方法本质上是你需要做的,但它可以更有效地完成。
您可以定义一组可帮助对数字进行分类的类别。 您不一定需要定义新类才能使其正常工作,但它有助于保持事情的整洁和井井有条。
class Category<T>
{
public Category(string name, Predicate<T> predicate)
{
Name = name;
Predicate = predicate;
}
public string Name { get; }
public Predicate<T> Predicate { get; }
}
然后,要对数字进行分组,您将执行以下操作:
var series = Enumerable.Range(1, 100);
var categories = new[]
{
new Category<int>("Prime", i => MyStaticMethods.IsPrime(i)),
new Category<int>("Odd", i => i % 2 != 0),
new Category<int>("Even", i => i % 2 == 0),
};
var grouped =
from i in series
from c in categories
where c.Predicate(i)
group i by c.Name;
这是使用反应式扩展的好情况,因为您将避免重复值。
在下面的代码中,"series"只被解析一次,因为它是一个热源,这要归功于 Publish()。
实际的解析是在"Connect()"期间完成的。
using System.Reactive.Linq;
var list = new List<KeyValuePair<string, int>>();
var series= Observable.Range(1, 100).Publish();
series.Where(e => e % 2 == 0).Subscribe(e=>list.Add(new KeyValuePair<string, int>("Even",e)));
series.Where(e => e % 2 == 1).Subscribe(e => list.Add(new KeyValuePair<string, int>("Odd", e)));
series.Where(e => MyStaticMethods.IsPrime(e) ).Subscribe(e => list.Add(new KeyValuePair<string, int>("Prime", e)));
series.Connect();
var result = list.GroupBy(n => n.Key);