如何使用条件 windows 而不是基于时间的 windows 将整数流拆分为缓冲区?
How can I split the integer stream into buffers using conditional windows instead of time based windows?
我有一个 returns 整数的 Observable,如下所示:
1, 1, 1, 1, -1, -1, -1, -1, 0, 0, 0, 0, -1, -1, -1, 0, 0, 0
我如何将此 Observable 转换为 return 那些整数数组,而不是按基于时间 windows 而是按基于值的拆分流?
这些整数是Unity更新事件中Touch的fingerId。它对于这项任务并不重要,但为了解释我为什么需要它,我必须提供这些细节。 -1 表示不接触。这就是差距。我需要删除那些 -1 部分并将流拆分为 fingerId 在“无触摸”时刻之间的缓冲区。我也可以这样描述:
Touch0, Touch0, Touch0, no Touch, no Touch, Touch1
无论是整数还是其他类型都没有关系。只需要将流分成缓冲区,删除 «window 值»。
这是我的代码,如果有帮助的话:
var leftSideTouchStream = Observable.EveryUpdate()
.Scan(-1, (id, _) =>
{
if (id < 0)
{
var leftSideTouches = Input.touches
.Where(t =>
t.phase == TouchPhase.Began
&& t.position.x < Screen.width / 2
);
return leftSideTouches.Any() ? leftSideTouches.First().fingerId : -1;
}
else
{
var touchEnded = Input.touches
.Any(t =>
t.fingerId == id &&
(t.phase == TouchPhase.Ended || t.phase == TouchPhase.Canceled)
);
return touchEnded ? -1 : id;
}
})
.Select(id =>
{
return Input.touches
.Where(t => t.fingerId == id)
.Select(t => new Nullable<Touch>(t))
.FirstOrDefault();
});
我需要与 Buffer 函数提供的行为完全相同,但正如我所说的,根据值而不是时间。
如果我有这个流:
1, 1, 1, 1, -1, -1, -1, -1, 0, 0, 0, 0, -1, -1, -1, 0, 0, 0
而«window值»为-1,则结果预计为:
[1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0]
可能存在一些更好的神奇解决方案,但我想最直接的是
private static int[][] GetArrays(int[] intputArray)
{
// use lists for dynamically adding elements
var outputLists = new List<List<int>>();
// initialize with the ignored value
var lastValue = -1;
// iterate over the inputArray
foreach (var value in intputArray)
{
// skip -1 values
if (value < 0)
{
lastValue = -1;
continue;
}
// if a new value begin a new list
if (lastValue != value)
{
outputLists.Add(new List<int>());
}
// add the value to the current (= last) list
outputLists[outputLists.Count - 1].Add(value);
// update the lastValue
lastValue = value;
}
// convert to arrays
// you could as well directly return the List<List<int>> instead
// and access the values exactly the same way
// but since you speak of buffers I guess you wanted arrays explicitely
var outputArrays = new int[outputLists.Count][];
for (var i = 0; i < outputLists.Count; i++)
{
outputArrays[i] = outputLists[i].ToArray();
}
return outputArrays;
}
所以打电话
var arrays = GetArrays(new int[]{1, 1, 1, 1, -1, -1, -1, -1, 0, 0, 0, 0, -1, -1, -1, 0, 0, 0});
应该导致
arrays[0] => [1, 1, 1, 1]
arrays[1] => [0, 0, 0, 0]
arrays[2] => [0, 0, 0]
因为你似乎更想动态地一个一个地添加值,所以我根本不会使用数组,而是使用类似
的东西
private List<List<int>> arrays = new List<List<int>>();
private int lastValue;
private void AddValue(int value)
{
// skip -1 values
if (value < 0)
{
lastValue = -1;
return;
}
// if a new value begin a new list
if (lastValue != value)
{
arrays.Add(new List<int>());
}
// add the value to the current (= last) list
arrays[outputLists.Count - 1].Add(value);
// update the lastValue
lastValue = value;
}
我的意思是你必须在某处存放一些东西
不幸的是,我没有找到任何 out-of-the-box 解决方案,所以我想出了自己的 Observable 实现:
using System;
using System.Collections.Generic;
using UniRx;
public static class ObservableFunctions
{
public static IObservable<T[]> BufferWhen<T>(this IObservable<T> source, Predicate<T> predicate)
{
return Observable.Create<T[]>(observer =>
{
List<T> buffer = new List<T>();
source.Subscribe(
t =>
{
if (predicate(t))
{
buffer.Add(t);
}
else
{
if (buffer.Count > 0)
{
observer.OnNext(buffer.ToArray());
buffer = new List<T>();
}
}
},
e =>
{
observer.OnError(e);
},
() =>
{
observer.OnCompleted();
}
);
return Disposable.Empty;
});
}
}
幸运的是它非常简单。比在 Google...
中搜索合适的函数更简单
我有一个 returns 整数的 Observable,如下所示:
1, 1, 1, 1, -1, -1, -1, -1, 0, 0, 0, 0, -1, -1, -1, 0, 0, 0
我如何将此 Observable 转换为 return 那些整数数组,而不是按基于时间 windows 而是按基于值的拆分流?
这些整数是Unity更新事件中Touch的fingerId。它对于这项任务并不重要,但为了解释我为什么需要它,我必须提供这些细节。 -1 表示不接触。这就是差距。我需要删除那些 -1 部分并将流拆分为 fingerId 在“无触摸”时刻之间的缓冲区。我也可以这样描述:
Touch0, Touch0, Touch0, no Touch, no Touch, Touch1
无论是整数还是其他类型都没有关系。只需要将流分成缓冲区,删除 «window 值»。
这是我的代码,如果有帮助的话:
var leftSideTouchStream = Observable.EveryUpdate()
.Scan(-1, (id, _) =>
{
if (id < 0)
{
var leftSideTouches = Input.touches
.Where(t =>
t.phase == TouchPhase.Began
&& t.position.x < Screen.width / 2
);
return leftSideTouches.Any() ? leftSideTouches.First().fingerId : -1;
}
else
{
var touchEnded = Input.touches
.Any(t =>
t.fingerId == id &&
(t.phase == TouchPhase.Ended || t.phase == TouchPhase.Canceled)
);
return touchEnded ? -1 : id;
}
})
.Select(id =>
{
return Input.touches
.Where(t => t.fingerId == id)
.Select(t => new Nullable<Touch>(t))
.FirstOrDefault();
});
我需要与 Buffer 函数提供的行为完全相同,但正如我所说的,根据值而不是时间。 如果我有这个流:
1, 1, 1, 1, -1, -1, -1, -1, 0, 0, 0, 0, -1, -1, -1, 0, 0, 0
而«window值»为-1,则结果预计为:
[1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0]
可能存在一些更好的神奇解决方案,但我想最直接的是
private static int[][] GetArrays(int[] intputArray)
{
// use lists for dynamically adding elements
var outputLists = new List<List<int>>();
// initialize with the ignored value
var lastValue = -1;
// iterate over the inputArray
foreach (var value in intputArray)
{
// skip -1 values
if (value < 0)
{
lastValue = -1;
continue;
}
// if a new value begin a new list
if (lastValue != value)
{
outputLists.Add(new List<int>());
}
// add the value to the current (= last) list
outputLists[outputLists.Count - 1].Add(value);
// update the lastValue
lastValue = value;
}
// convert to arrays
// you could as well directly return the List<List<int>> instead
// and access the values exactly the same way
// but since you speak of buffers I guess you wanted arrays explicitely
var outputArrays = new int[outputLists.Count][];
for (var i = 0; i < outputLists.Count; i++)
{
outputArrays[i] = outputLists[i].ToArray();
}
return outputArrays;
}
所以打电话
var arrays = GetArrays(new int[]{1, 1, 1, 1, -1, -1, -1, -1, 0, 0, 0, 0, -1, -1, -1, 0, 0, 0});
应该导致
arrays[0] => [1, 1, 1, 1]
arrays[1] => [0, 0, 0, 0]
arrays[2] => [0, 0, 0]
因为你似乎更想动态地一个一个地添加值,所以我根本不会使用数组,而是使用类似
的东西private List<List<int>> arrays = new List<List<int>>();
private int lastValue;
private void AddValue(int value)
{
// skip -1 values
if (value < 0)
{
lastValue = -1;
return;
}
// if a new value begin a new list
if (lastValue != value)
{
arrays.Add(new List<int>());
}
// add the value to the current (= last) list
arrays[outputLists.Count - 1].Add(value);
// update the lastValue
lastValue = value;
}
我的意思是你必须在某处存放一些东西
不幸的是,我没有找到任何 out-of-the-box 解决方案,所以我想出了自己的 Observable 实现:
using System;
using System.Collections.Generic;
using UniRx;
public static class ObservableFunctions
{
public static IObservable<T[]> BufferWhen<T>(this IObservable<T> source, Predicate<T> predicate)
{
return Observable.Create<T[]>(observer =>
{
List<T> buffer = new List<T>();
source.Subscribe(
t =>
{
if (predicate(t))
{
buffer.Add(t);
}
else
{
if (buffer.Count > 0)
{
observer.OnNext(buffer.ToArray());
buffer = new List<T>();
}
}
},
e =>
{
observer.OnError(e);
},
() =>
{
observer.OnCompleted();
}
);
return Disposable.Empty;
});
}
}
幸运的是它非常简单。比在 Google...
中搜索合适的函数更简单