reactivex повторный пропуск между

Предположим, у меня есть следующий поток данных:

1, 2, 3, a, 5, 6, b, 7, 8, a, 10, 11, b, 12, 13, ...

Я хочу отфильтровать все между «а» и «б» (включительно), независимо от того, сколько раз они появляются. Таким образом, результатом вышеизложенного будет:

1, 2, 3, 7, 8, 12, 13, ...

Как я могу сделать это с ReactiveX?


person melston    schedule 28.05.2017    source источник


Ответы (2)


Используйте сканирование с начальным значением b, чтобы включить

1, 2, 3, a, 5, 6, b, 7, 8, a, 10, 11, b, 12, 13, ...

в

b, 1, 2, 3, a, a, a, b, 7, 8, a, a, a, b, 12, 13, ...

а затем отфильтровать a и b, чтобы получить

1, 2, 3, 7, 8, 12, 13, ...

В псевдокоде

values.scan('b', (s, v) -> if (v == 'a' || v == 'b' || s != 'a') v else s). filter(v -> v != 'a' && v != 'b');

person Heikki Vesalainen    schedule 03.06.2017
comment
Выдающийся. Я полностью пропустил использование сканирования для такого рода вещей. - person melston; 04.06.2017

ХОРОШО. Я публикую это на случай, если кому-то еще нужен ответ на него. Немного другая настройка, чем я описал выше, просто чтобы было легче понять.

List<String> values = new List<string>()
{
    "1", "2", "3",
    "a", "5", "6", "b", 
    "8", "9", "10", "11",
    "a", "13", "14", "b",
    "16", "17", "18", "19",
    "a", "21", "22", "b",
    "24"
};

var aa = 
    // Create an array of CSV strings split on the terminal sigil value
    String.Join(",", values.ToArray())
    .Split(new String[] { "b," }, StringSplitOptions.None)

    // Create the observable from this array of CSV strings
    .ToObservable()

    // Now create an Observable from each element, splitting it up again
    // It is no longer a CSV string but the original elements up to each terminal value
    .Select(s => s.Split(',').ToObservable()
        // From each value in each observable take those elements
        // up to the initial sigil
        .TakeWhile(s1 => !s1.Equals("a")))

    // Concat the output of each individual Observable - in order
    // SelectMany won't work here since it could interleave the
    // output of the different Observables created above.
    .Concat();

aa.Subscribe(s => Console.WriteLine(s));

Это распечатывает:

1
2
3
8
9
10
11
16
17
18
19
24

Это немного более запутанно, чем я хотел, но это работает.

Редактировать 03.06.17:

Я действительно нашел более чистое решение для моего случая.

List<String> values = new List<string>()
{
    "1", "2", "3",
    "a", "5", "6", "b", 
    "8", "9", "10", "11",
    "a", "13", "14", "b",
    "16", "17", "18", "19",
    "a", "21", "22", "b",
    "24"
};

string lazyABPattern = @"a.*?b";
Regex abRegex = new Regex(lazyABPattern);

var bb = values.ToObservable()
    .Aggregate((s1, s2) => s1 + "," + s2)
    .Select(s => abRegex.Replace(s, ""))
    .Select(s => s.Split(',').ToObservable())
    .Concat();
bb.Subscribe(s => Console.WriteLine(s));

Код проще, что упрощает его использование (даже несмотря на то, что он использует регулярные выражения).

Проблема здесь в том, что это все еще не является общим решением проблемы удаления «повторяющихся областей» потока данных. Он основан на преобразовании потока в одну строку, работе со строкой, а затем преобразовании ее обратно в какую-либо другую форму. Если у кого-то есть какие-либо идеи о том, как подойти к этому в целом, я хотел бы услышать об этом.

person melston    schedule 02.06.2017