如何实现一种在数组中查找连续连续值段的算法?
假设我们从以下数组开始:
array = [5, 6, 4, 0, 5, 10, 12, 10, 11, 4, 3, 2, 3, 2, 1, 3, 1, 0, 2]
我们还假设我们将在每个最大值为3的段中容忍“接近”。
产生的段将类似于以下内容:
seg[0] = [5, 6, 4]
seg[1] = [0]
seg[2] = [5]
seg[3] = [10, 12, 10, 11]
seg[4] = [4, 3, 2, 3, 2]
seg[5] = [1, 3, 1]
seg[6] = [0, 2]
此外,我们可以允许“丢失”,例如最大一个连续值,该值将落在当前段之外,但如果以下值适合该段,则将其包括在内。会产生类似以下内容:
seg[0] = [5, 6, 4, 0, 5] //include 0 as a "dropout"
seg[1] = [10, 12, 10, 11]
seg[3] = [4, 3, 2, 3, 2, 1, 3] // include 1 as a "dropout"
seg[4] = [1, 3, 1, 0, 2] // include 0 as a "droput"
关于如何实现这种算法的想法?
答案 0 :(得分:0)
这是我自己的看法。用Haxe (haxe.org)写。
checkDropout()
方法检查长度为n的“缺失”,并将其“归一化”为当前片段的平均值。
using Lambda;
class Example {
static function main() {
var a:Array<Float> = [5, 6, 4, 0, 5, 10, 12, 10, 11, 4, 3, 2, 3, 2, 1, 3, 1, 0, 2];
// Segment value tolerance of 2
// Dropout max length of 3
var segmentor = new Segmentor(2, 3);
// Callback for displaying result
segmentor.displayResult = (r, v) -> {
trace('-------------------------------------');
trace('value added: ' + v);
trace('result: ' + r);
}
// Feed the segmentor with the example values
a.map(i -> segmentor.addNumber(i));
// var result = [
// [5, 6, 4, 5, 5],
// [10, 12, 10, 11],
// [4, 3, 2, 3, 2],
// [1, 3, 1],
// [0, 2]
// ];
}
}
class Segmentor {
public function new(valueSpan:Int = 2, dropoutLength:Int = 1) {
this.valueSpan = valueSpan;
this.dropoutLength = dropoutLength;
this.result = [];
this.result.push([]);
}
var dropoutLength:Int = null;
var valueSpan:Int = null;
public var result(default, null):Array<Array<Float>>;
public function addNumber(v:Float) {
this.processNumber(v);
}
function processNumber(v:Float) {
var current = this.result[this.result.length - 1];
if (current.length == 0) {
current.push(v);
} else if (fitIn(current, v) || this.checkDropout(v)) {
var current2 = this.result[this.result.length - 1];
current2.push(v);
} else {
this.result.push([v]);
}
this.displayResult(this.result, v);
}
dynamic public function displayResult(result:Array<Array<Float>>, valueAdded:Float) {}
function checkDropout(v:Float):Bool {
if (this.result.length <= 1)
return false;
var last = this.result[this.result.length - 1];
if (last.length <= this.dropoutLength) {
var prev = this.result[this.result.length - 2];
if (fitIn(prev, v)) {
var mid = mid(prev);
var newLast = [for (i in 0...last.length) mid];
newLast.map(n -> prev.push(n));
this.result.pop();
return true;
}
}
return false;
}
function fitIn(a:Array<Float>, v:Float):Bool {
var max = a.fold((c, v) -> Math.max(v, c), a[0]);
var min = a.fold((c, v) -> Math.min(v, c), a[0]);
var fit = ((max - v <= this.valueSpan) && (v - min <= this.valueSpan));
return fit;
}
function mid(a:Array<Float>) {
var max = a.fold((c, v) -> Math.max(v, c), a[0]);
var min = a.fold((c, v) -> Math.min(v, c), a[0]);
return min + (max - min) / 2;
}
}