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 Réponses :
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:
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
. 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
. 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.
Merci, je vais essayer!
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() );
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(); } }); });
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.