You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于缓冲项的条件使用Observable.Buffer进行序列缓冲?

问题

我想根据依赖当前项的条件对序列中的元素进行缓冲,规则如下:

  • 遇到奇数时停止缓冲
  • 遇到偶数时开始缓冲

给定输入序列:

new[] { 1, 3, 5, 7, 2, 4, 6, 8, 1 };

期望输出的缓冲结果:

{ 1 }
{ 3 }
{ 5 }
{ 7 }
{ 2, 4, 6, 8 }
{ 1 }

我尝试了以下代码但没有得到预期结果:

var boundaries = origin.Select(x => x % 2 != 0).DistinctUntilChanged();
var result = origin.Buffer(boundaries);
解决方案

你原代码的问题在于,Buffer(boundaries)的边界逻辑不符合你的分组规则:Buffer会把边界信号作为分隔点,但你的需求是奇数单独成组、偶数连续成组,原逻辑没处理好分组的起始与结束时机。

方法一:手动遍历分组(直观易懂)

如果不需要依赖Rx的响应式操作符,直接遍历序列手动维护缓冲是最清晰的方式:

var origin = new[] { 1, 3, 5, 7, 2, 4, 6, 8, 1 };
var result = new List<List<int>>();
List<int> currentBuffer = null;

foreach (var num in origin)
{
    if (num % 2 != 0)
    {
        // 遇到奇数:若有未完成的偶数缓冲,先提交;再将当前奇数单独成组
        if (currentBuffer != null)
        {
            result.Add(currentBuffer);
            currentBuffer = null;
        }
        result.Add(new List<int> { num });
    }
    else
    {
        // 遇到偶数:初始化或追加到当前缓冲
        currentBuffer ??= new List<int>();
        currentBuffer.Add(num);
    }
}

// 处理最后剩余的偶数缓冲
if (currentBuffer != null)
{
    result.Add(currentBuffer);
}

方法二:Rx响应式实现

如果要基于Rx操作符实现,可以用Window配合自定义边界逻辑,精准控制分组的开始与结束:

var origin = new[] { 1, 3, 5, 7, 2, 4, 6, 8, 1 }.ToObservable();

var result = origin
    .Window(() => origin
        .Skip(1)
        .Where(x => 
            // 边界触发条件:下一个元素是奇数,或者下一个元素是偶数且当前元素是奇数
            x % 2 != 0 || (x % 2 == 0 && origin.Take(1).First() % 2 != 0)
        )
    )
    .SelectMany(window => window.ToList());

原代码失败原因

原代码中boundaries是奇偶状态变化的信号,但Buffer会在每次边界触发时结束当前缓冲并开启新缓冲,这会导致:

  • 第一个奇数触发边界时,缓冲为空;第二个奇数触发时,缓冲里是前一个奇数,分组结果完全不符合预期
  • 偶数起始的边界信号没有对应到正确的分组起始点,逻辑完全混乱

内容的提问来源于stack exchange,提问作者SuperJMN

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 01:01:19