3

我有一个收藏。我想选择符合 2 个条件的值。

var a;
var b;
foreach(SomeObject so in collection)
{
    if(so.Value == something) 
    {
        a = so;
        // break if b is not null.
    }
    else if(so.Value == somethingElse) 
    {
        b = so;
        // break if a is not null
    }
}

是否可以使用 linq 仅对集合进行一次迭代来执行上述操作?如果我们可以使用这个事实,那么某物只有一个值,而某物只有一个值。

4

6 回答 6

3

此解决方案将列表缩小到两个元素,然后从那里开始。 Take(2)使用,因此仅在找到两个值之前搜索集合。

var matches = collection.Where(x => x.Value == something || x.Value == somethingElse)
                        .Take(2)
                        .ToList();
var a = matches.Single(x => x.Value == something);
var b = matches.Single(x => x.Value == somethingElse);
于 2012-08-30T02:04:28.873 回答
2
var relevant =
  from so in l where so.Value == something || so.Value == somethingElse
  group so by so.Value == something into grp
  select new {ForA = grp.Key, SO = grp.First()};
foreach(var bit in relevant)
  if(bit.ForA)
    a = bit.SO;
  else
    b = bit.SO;

它可以针对某些来源为您带来一些好处,因为只检索了两个项目,但如果针对内存中的一个集合,我会保留您所拥有的,但是添加一个 catch 以便一旦您同时设置了aand b,您就会停止循环而不是一直不必要地检查收藏品。

于 2012-08-30T01:46:45.243 回答
2

你需要这样的东西:

var a = collection.OfType<YourCollectionElementType>().FirstOrDefault(i=>i.Equals(something));
var b = collection.OfType<YourCollectionElementType>().FirstOrDefault(i=>i.Equals(somethingelse));

您的集合IEnumerable至少应该实现能够使用此代码。这取决于您的收藏类型。如果它实现了 generic IEnumerable<T>,比如说它List<YourCollectionElementType>或者一个数组YourCollectionElementType[],那么你就不需要使用OfType<T>,即

var a = collection.FirstOrDefault(i=>i.Equals(something));
var b = collection.FirstOrDefault(i=>i.Equals(somethingelse));

如果您的收藏不包含该值,a和/或b将获得null值。

实际上,您可以在 MSDN 中阅读所有这些内容。LINQ 并不难学,如果你尝试例如:

  1. Enumerable.FirstOrDefault 方法 (IEnumerable)

  2. Enumerable.OfType 方法

编辑

在您的评论中,您说的是可以保证只有一个值存在。您需要两个单独的变量是否非常重要?你可以像这样得到现值:

object thevalue = collection.FirstOrDefault(i => i == something || i == somethingelse);

编辑

实际上,我会让你的循环保持原样,只添加了这样的一行:

SomeObject a;
SomeObject b;
foreach(SomeObject so in collection)
{
    if(so.Value == something)
        a = so;
    else if(so.Value == somethingElse)
        b = so;
    if(a!=null && b!=null)
        break;
}

如果只期望其中一个值,那么

SomeObject a;
SomeObject b;
foreach(SomeObject so in collection)
{
    if(so.Value == something)
    {
        a = so;
        break;
    }
    else if(so.Value == somethingElse)
    {
        b = so;
        break;
    }
}
于 2012-08-30T00:21:18.040 回答
1

你可以这样做:

collection
    .Select(x => x.Value == something
        ? () => a = x
        : (x.Value == somethingElse
            ? () => b = x 
            : (Action)null))
    .Where(x => x != null)
    .ToArray()
    .ForEach(x => x());

我测试了这段代码,它奏效了。

如果集合在某处的数据库中,那么我建议这样做:

collection
    .Where(x => x.Value == something || x.Value == somethingElse)
    .ToArray()
    .Select(x => x.Value == something
        ? () => a = x
        : (x.Value == somethingElse
            ? () => b = x 
            : (Action)null))
    .Where(x => x != null)
    .ToArray()
    .ForEach(x => x());
于 2012-08-30T01:54:31.630 回答
0

不确定如果我理解您的问题但假设Something并且SomethingElse是值类型并且在运行时之前已知,您可以在一个语句中执行以下操作。

        var FindItems = new[]
        {
            new SomeObject { Value = "SomethingElse" }
        };

        var CollectionItems = new[]
        {
            new SomeObject { Value = "Something" },
            new SomeObject { Value = "SomethingElse" }
        };

        var qSomeObject = CollectionItems
                          .Where(c => FindItems.Any(x => c.Value == x.Value));
于 2012-08-30T02:35:00.330 回答
0

当然可以,但我不推荐。拥有你的循环会更干净,因为你现在已经拥有它。

如果你真的想知道怎么做,你可以这样做:

class SomeObject
{
    public string Value { get; set; }
}
var items = new[]
{
    new SomeObject { Value = "foo" },
    new SomeObject { Value = "bar" },
    new SomeObject { Value = "baz" },
};

var something = "foo";
var somethingElse = "baz";
var result = items.Aggregate(
    Tuple.Create(default(SomeObject), default(SomeObject)),
    (acc, item) => Tuple.Create(
        item.Value == something     ? item : acc.Item1,
        item.Value == somethingElse ? item : acc.Item2
    )
);
// result.Item1 <- a == new SomeObject { Value = "foo" }
// result.Item2 <- b == new SomeObject { Value = "baz" }
于 2012-08-30T01:20:34.157 回答