2
votes

Comment utiliser un IObservable pour segmenter un IObservable en un IObservable de longueur variable

J'ai un IObservable "values" qui renvoie des éléments T qui doivent être combinés en séquence dans des tableaux de longueur variable, et j'ai un contrôle " "IObservable qui me dit combien de temps le tableau suivant doit durer. Supprimer un élément, le répéter ou obtenir les résultats dans le désordre rendra les résultats dénués de sens.

C'est pour un projet de robotique connecté en série que je réécris dans Rx.NET.

-[A]-[AB]-[ABCD]->

J'aimerais voir quelque chose comme ceci:

values  ----A--B--C--D--E--F--G--H-->
control --1-----4---------------2--->
result  ---[A]---------[BCDE]--[FG]->

Mais ma tentative jusqu'à présent aboutit à p >

IObservable<char> values = new [] {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H' }.ToObservable();
IObservable<int> control = new [] { 1, 4, 2 }.ToObservable();
IObservable<char[]> result = control.SelectMany(length => values.Take(length).ToArray());


3 commentaires

Est-il acceptable / possible que vous puissiez définir des sujets d'assistance qui seront déclenchés / remplis par des abonnements à partir des observables d'origine?


Absolument, si cela fonctionne, je suis prêt à l'essayer. Comment pourrais-je faire ça?


Hmm, je pense avoir une idée de la façon de procéder, ou du moins une idée de l'endroit où chercher. Je vais bricoler et faire rapport.


3 Réponses :


0
votes

Vous pouvez créer plusieurs sujets d'aide pour préparer / créer de nouveaux observables afin de construire le nouvel observable que vous souhaitez. Vous pouvez créer des sujets pour ces types d'observables:

  1. Créez une nouvelle observable qui répète une valeur unique le nombre égal au nombre lu depuis le contrôle . À partir de (1, 4, 2) , vous obtiendrez (guid_1, guid_2, guid_2, guid_2, guid_2, guid_3, guid_3) . Appelez cet observable repeatSize .
  2. Utilisez l'opérateur Zip () pour combiner une valeur de chacune des valeurs repeatSize et . Vous obtiendrez une observable avec les valeurs: ((A, guid_1), (B, guid_2), (C, guid_2), (D, guid_2), (E, guid_2), (F, guid_3), ( G, guid_3)) . Appelez cette observable zippedValues ​​.
  3. Abonnez-vous sur zippedValues ​​ et mettez / ajoutez la valeur d'origine dans une liste. Enregistrez également la valeur précédente de l'observable repeatSize . Comparez-le avec la valeur actuelle de repeatSize . Quand il a été changé (comme de guid_2 à guid_3 ), vous savez que vous avez atteint la fin / le début, vous pouvez donc envoyer la liste remplie à un nouvel observable. Après cela, vous réinitialisez à nouveau la liste et recommencez à la remplir.

Vous devrez peut-être créer 2-3 objets Subject , vous y abonner et utiliser plusieurs appels OnNext () pour les remplir à partir de l'abonnement d'autres observables.


1 commentaires

Merci, je vais essayer!



0
votes

Je n'ai pas testé cela, mais je pense que vous pouvez combiner Zip () et Scan () pour produire le résultat que vous avez demandé.

IObservable<char> values = new [] {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H' }.ToObservable();
IObservable<int> control = new [] { 1, 4, 2 }.ToObservable();
IObservable<char[]> result = control.Zip(
    control.Scan(values, (rest, length) => rest.Skip(length)),
    (length, vals) => vals.Take(length).ToArray()
);


0 commentaires

1
votes

D'accord, voici le code qui répond à tous mes besoins. Progman, vous avez contribué à faire ce travail avec vos conseils. Le voici, enveloppé dans un Observable.Create bien rangé et transformé en méthode d'extension sur IObservable , avec un jetable qui supprime l'abonnement sur la séquence zippée .

values  ----A--B--C--D--E--F--G--H--I--J--K--L--M--N--O--P-->
control --1-4-2-0-3-3--------------------------------------->
result  ---[A]---------[BCDE]-[FG]----[HIJ]----[KLM]-------->

Exemple de sortie:

    public static IObservable<T[]> Chop<T>(this IObservable<T> values, IObservable<int> control) =>
        Observable.Create<T[]>(observer => 
        {
            List<T> buffer = new List<T>();
            return values.Zip(control.SelectMany(length => Enumerable.Repeat(length, length)), 
                              (value, length) => (value, length))
                         .Subscribe(next => 
                         {
                             buffer.Add(next.value);
                             if (buffer.Count == next.length)
                             {
                                 observer.OnNext(buffer.ToArray());
                                 buffer.Clear();
                             }
                         });
        });


0 commentaires