当前位置:  开发笔记 > 编程语言 > 正文

LINQ语句,其中结果计数用于表达式的条件

如何解决《LINQ语句,其中结果计数用于表达式的条件》经验,为你挑选了1个好方法。

O'LinQ-fu大师,请帮忙.

我有一个要求,我必须使用VB.NET中的Target.AddRange()从IEnumerable(Of T)(让我们称之为Source)将项添加到List(Of T)(让我们称之为Target).

Target.AddRange(Source.TakeWhie(Function(X, Index) ?))

的?part是一个棘手的条件,例如:只要尚未列举的计数不等于将列表填充到所需的最小值,然后随机决定是否应该采用当前项目,否则采取该项目. Somethig喜欢......

Source.Count() - Index = _minimum_required - _curr_count_of_items_taken _
OrElse GetRandomNumberBetween1And100() <= _probability_this_item_is_taken
' _minimum_required and _probability_this_item_is_taken are constants

令人困惑的部分是每次满足TakeWhile语句时都需要递增_curr_count_of_items_taken.我该怎么做呢?

我也对使用任何其他LINQ方法(Aggregate,Where等)而不是TakeWhile的解决方案持开放态度.

如果所有其他方法都失败了,那么我将回到使用一个好的旧的for-loop =)

但希望有一个LINQ解决方案.在此先感谢您的任何建议.

编辑:请求的旧的for-loop版本:

Dim _source_total As Integer = Source.Count()
For _index As Integer = 0 To _source_total - 1
    If _source_total - _index = MinimumRows - Target.Count _
    OrElse NumberGenerator.GetRandomNumberBetween1And100 <= _possibility_item_is_taken Then
        Target.Add(Source(_index))
    End If
Next

编辑:大卫的无副作用答案接近我需要的同时保持可读性.也许他是唯一一个能理解我传达不良的伪代码的人.事后看来,OrderBy(GetRandomNumber)非常出色.我只需要将Take(3)部分更改为Take(MinimumRequiredPlusAnOptionalRandomAmountExtra)并在结尾处删除OrderBy和Select.感谢其他人的建议.



1> Jon Skeet..:

基本上你需要引入副作用.

在C#中,这相对容易 - 您可以使用lambda表达式来更新捕获的变量.在VB中,这可能仍然存在,但我不想猜测语法.我不太了解你的情况(听起来有点倒退),但你可以这样做:

C#会是这样的:

int count = 0;

var query = source.TakeWhile(x => count < minimumRequired ||
                                  rng.Next(100) < probability)
                  .Select(x => { count++; return x; });

target.AddRange(query);

每次实际拍摄物品时,计数都会增加.

请注意,我怀疑你真的想要Where而不是TakeWhile- 否则第一次rng给出一个高数字,序列将结束.

编辑:如果你不能直接使用副作用,你可能会使用一个可怕的黑客.我没试过这个,但......

public static T Increment(ref int counter, T value)
{
    counter++;
    return value;
}

...

int count = 0;
var query = source.TakeWhile(x => count < minimumRequired ||
                                  rng.Next(100) < probability)
                  .Select(x => Increment(ref count, x));

target.AddRange(query);

换句话说,您将副作用放入单独的方法中,并使用计数器的pass-by-reference调用该方法.不知道它是否适用于VB,但可能值得一试.另一方面,循环可能更简单......

作为一种完全不同的接近它的方式,您的源是否已经是内存中的集合,您可以廉价地迭代它?如果是这样,只需使用:

var query = Enumerable.Concat(source.Take(minimumRequired),
                              source.Skip(minimumRequired)
                                    .TakeWhile(condition));

换句话说,绝对抓住前n个元素,然后再次开始,跳过前n个元素并根据条件取其余元素.

推荐阅读
女女的家_747
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有