如何找到数组中封闭值的分段?

时间:2018-11-27 09:00:25

标签: arrays

如何实现一种在数组中查找连续连续值段的算法?

假设我们从以下数组开始:

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"

关于如何实现这种算法的想法?

1 个答案:

答案 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;
    }
}