Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linq IEnumerable扩展方法-如何提高性能?_Linq - Fatal编程技术网

Linq IEnumerable扩展方法-如何提高性能?

Linq IEnumerable扩展方法-如何提高性能?,linq,Linq,我编写了以下扩展方法,用于查找满足传递给它的谓词的连续的项序列。序列中连续项目的数量由参数“sequenceSize”确定 例如,我可能有一个整数的IEnumerable,我想找到10个大于100的连续值。此扩展方法将确定是否存在这样的序列 这种方法效果很好。但是,由于它必须执行的操作,如果IEnumerable中有相当数量的元素,则速度可能会很慢,因为它必须从第一个元素开始,查找满足谓词的连续值,然后转到第二个元素并执行相同的操作,等等 我正在寻找如何加快这一进程的建议。我尝试使用Aspare

我编写了以下扩展方法,用于查找满足传递给它的谓词的连续的项序列。序列中连续项目的数量由参数“sequenceSize”确定

例如,我可能有一个整数的IEnumerable,我想找到10个大于100的连续值。此扩展方法将确定是否存在这样的序列

这种方法效果很好。但是,由于它必须执行的操作,如果IEnumerable中有相当数量的元素,则速度可能会很慢,因为它必须从第一个元素开始,查找满足谓词的连续值,然后转到第二个元素并执行相同的操作,等等

我正在寻找如何加快这一进程的建议。我尝试使用Asparell(),但没有效果

public static IEnumerable<IEnumerable<T>> FindSequenceConsecutive<T>(this IEnumerable<T> sequence, 
                                                                     Predicate<T> predicate, 
                                                                     int sequenceSize)
{
    IEnumerable<T> current = sequence;

    while (current.Count() > sequenceSize)
    {
        IEnumerable<T> window = current.Take(sequenceSize);

        if (window.Where(x => predicate(x)).Count() >= sequenceSize)
            yield return window;

        current = current.Skip(1);
    }
}
公共静态IEnumerable FindSequenceConsecutive(此IEnumerable序列,
谓词,
int sequenceSize)
{
IEnumerable current=序列;
while(current.Count()>sequenceSize)
{
IEnumerable窗口=当前.Take(sequenceSize);
if(window.Where(x=>谓词(x)).Count()>=sequenceSize)
收益返回窗;
当前=当前。跳过(1);
}
}

此方法缓慢的最可能原因是重复调用
.Count()
,它将立即枚举序列以确定元素的数量

您最好明确地测试标准并跟踪计数,而不是重复使用
Where()
Count()

通常,此方法会大量枚举序列。如果调用
.ToList()
枚举一次序列,然后对生成的列表执行操作,可能会获得很好的加速效果。(请注意,如果希望在无限长序列上使用此方法,则此方法不起作用。)

更新:您正在测试
>=sequenceSize
,即使
window.Count()==sequenceSize
。换句话说,您只需要
All()

不确定这会有多大帮助,但至少在语义上更清楚

<强>进一步编辑< /强>:考虑此方法:

public static IEnumerable<IEnumerable<T>> FindSequenceConsecutive<T>(this IEnumerable<T> sequence, Predicate<T> predicate, int sequenceSize)
{
    List<T> list = sequence.ToList();
    List<bool> matchList = list.Select(x => predicate(x)).ToList();

    int start = 0;
    int count = list.Count;

    while (start + sequenceSize <= count)
    {
        var range = matchList.GetRange(start, sequenceSize);
        if (range.All(x => x))
            yield return list.GetRange(start, sequenceSize);

        start++;
    }
}
public static IEnumerable FindSequenceConsecutive(此IEnumerable序列,谓词谓词,int sequenceSize)
{
List=sequence.ToList();
List matchList=List.Select(x=>predicate(x)).ToList();
int start=0;
int count=list.count;
while(开始+顺序大小x))
收益返回列表.GetRange(开始,sequenceSize);
启动++;
}
}

它对序列求值一次,然后划分一个必要的列表。

我认为这样的方法可能适合您,因为您可以遍历列表一次,基本上保持一个连续的项目队列,通过谓词,根据需要清除(全部)和出列(一个)

public static IEnumerable<IEnumerable<T>> FindSequenceConsecutive<T>(this IEnumerable<T> sequence, Predicate<T> predicate, int sequenceSize)
{
    var queue = new Queue<T>();

    foreach (T item in sequence)
    {
        if (predicate(item))
        {
            queue.Enqueue(item);
            if (queue.Count == sequenceSize)
            {
                yield return queue.ToList();
                queue.Dequeue();
            }
        }
        else
        {
            queue.Clear();
        }
    }
}
屈服

3,4,5
8,3,5
3,5,6

我相信这个解决方案将提供最好的性能,并且随着序列变大,扩展性会更好,因为它不分配任何额外的缓冲区(列表或队列),也不必将结果转换为列表或对结果缓冲区进行任何计数。另外,它只在序列上迭代一次

public static IEnumerable<IEnumerable<T>> FindSequenceConsecutive<T>(this IEnumerable<T> sequence,
    Predicate<T> predicate, int sequenceSize)
{
    IEnumerable<T> window = Enumerable.Repeat(default(T), 0);

    int count = 0;

    foreach (var item in sequence)
    {
        if (predicate(item))
        {
            window = window.Concat(Enumerable.Repeat(item, 1));
            count++;

            if (count == sequenceSize)
            {
                yield return window;
                window = window.Skip(1);
                count--;
            }
        }
        else
        {
            count = 0;
            window = Enumerable.Repeat(default(T), 0);
        }                
    }
}
公共静态IEnumerable FindSequenceConsecutive(此IEnumerable序列,
谓词谓词,int sequenceSize)
{
IEnumerable window=Enumerable.Repeat(默认值(T),0);
整数计数=0;
foreach(序列中的var项目)
{
if(谓语(项))
{
window=window.Concat(可枚举.重复(第1项));
计数++;
如果(计数==序列大小)
{
收益返回窗;
窗口=窗口。跳过(1);
计数--;
}
}
其他的
{
计数=0;
窗口=可枚举。重复(默认值(T),0);
}                
}
}

+1。我不能说,
所有的
是否都会产生可测量的影响,但这至少意味着你没有击中序列中的每个元素。如果您有一长串不符合筛选谓词的元素,这可能是一个很大的优点。@dlev-我不知道您的解决方案是如何工作的。我正在寻找连续的值。您的“匹配列表”实现似乎无法找到连续的值;我已经测试过:)匹配列表本质上是对序列的每个成员调用谓词的结果的缓存
matchList[i]==谓词(list[i])
@dlev-它确实有效,而且速度非常快。干得好!谢谢。这是一个很好的努力,但这错过了序列。如果您有5个连续项通过谓词([a,b,c,d,e]),并且正在寻找3的序列,您将得到[a,b,c],但不是[b,c,d]和[c,d,e]。其次,我不确定可伸缩性的说法,但我不能太挑剔,因为我绝不是专家。但是像Enumerable.Repeat这样的方法也会创建垃圾,创建并填充类。Linq不是搭便车。@Anthony你发表了我的评论!事实上,我对你的答案投了更高的票,我很肯定这是最好的选择。@Anthony Shoot,你说得对。需要添加
Skip()
或其他内容。呜呜。我只要向后滚,吉姆就能处理它。:)@Anthony-修复了该错误,现在它与您的解决方案基本相同,但更详细:-(,你的更优雅。我对两者进行了性能测试,即使在非常大的序列中,它们也完全相同,而你的解决方案在原始序列中赢得了超过26K个元素的1ms!因此,我猜这将归结为如何呈现结果的偏好。在你的解决方案中,“窗口”已经在
3,4,5
8,3,5
3,5,6
public static IEnumerable<IEnumerable<T>> FindSequenceConsecutive<T>(this IEnumerable<T> sequence,
    Predicate<T> predicate, int sequenceSize)
{
    IEnumerable<T> window = Enumerable.Repeat(default(T), 0);

    int count = 0;

    foreach (var item in sequence)
    {
        if (predicate(item))
        {
            window = window.Concat(Enumerable.Repeat(item, 1));
            count++;

            if (count == sequenceSize)
            {
                yield return window;
                window = window.Skip(1);
                count--;
            }
        }
        else
        {
            count = 0;
            window = Enumerable.Repeat(default(T), 0);
        }                
    }
}