8
votes

"Décompressez" iénumérables dynamiquement en C # ou une meilleure alternative

permet de supposer que vous avez une fonction qui renvoie un objet énuméré étalé: xxx

Vous avez également deux fonctions qui consomment deux iEnumerables S, par exemple: xxx

Comment pouvez-vous appeler consommationchicken et consommation sans a) convertir ferme () Tolist () à l'avance parce qu'il pourrait avoir deux enregistrements de zillion, b) pas de multi-filetage.

essentiellement: xxx

mais sans forcer la double énumération.

Je peux le résoudre avec multithread, mais il devient inutilement compliqué avec une file d'attente tampon pour chaque liste.

Donc, je cherche un moyen de diviser le animalcount < / Code> Enumerator en deux int énumérateurs sans évaluer complètement animalCount . Il n'y a pas de problème à exécuter consommé et consomméchicken ensemble dans l'étape de verrouillage.

Je peux sentir la solution juste hors de ma saisie mais je ne suis pas assez là-bas. Je pense dans le sens des lignes d'une fonction d'assistance qui renvoie un iEnumerable être introduit dans consommationCHicken et chaque fois que l'itérateur est utilisé, il appelle en interne consommation , exécutant ainsi les deux fonctions dans l'étape de verrouillage. Sauf bien sûr, je ne veux pas appeler consommation plus d'une fois.


4 commentaires

Arrêter. Prendre une profonde inspiration. Organiser vos pensées de manière logique. Vous avez sauté de animalcount à ienumerable à ienumerable (je suppose? Ne peut même pas dire à votre intention ...) . Comme cela se tient maintenant se fait pavillon comme non une vraie question.


Pourquoi les combinez-vous dans animalCount en premier lieu.


@Daniel permet de dire que ce n'est pas que je les combine. À partir d'une source extérieure, un fichier journal de ligne de zillion avec chickencount et Goatcount sur chaque ligne. Et j'ai deux fonctions séparées de 3ème partie qui souhaitent que leurs données soient iesumérables.


Nous ne sommes donc pas autorisés à stocker la moitié de la matrice en stockage temporaire de quelque nature que ce soit?


4 Réponses :


4
votes

Je ne pense pas qu'il y ait un moyen de faire ce que vous voulez, puisque consommationChickens (iEnumerable ) code> et consommation (iEnumerable ) code> est en train d'être appelé séquentiellement, chacun d'entre eux énumérant une liste séparément - Comment vous attendez-vous à ce que cela fonctionne sans deux énumérations distinctes de la liste?

Selon la situation, une meilleure solution consiste à avoir consommationchicken (int) code > et consumeegoat (int) code> méthodes (qui consomment chacun un article STROPT> article fort> em>, et appelez-les à l'alternance. Comme ceci: p> xxx pré>

ceci énumérera la collection code> une seule fois. P>


aussi, une note: Selon Sur votre fournisseur de Linq et que c'est exactement que vous essayez de faire, il peut y avoir de meilleures options. Par exemple, si vous essayez d'obtenir la somme totale des deux poulets et des chèvres d'une base de données à l'aide de Linq-to-SQL ou de Linq-to-entités, la requête suivante ... P>

from a in animals
group a by 0 into g
select new 
{
    TotalChickens = g.Sum(x => x.Chickens), 
    TotalGoats = g.Sum(x => x.Goats)
}


1 commentaires

Merci pour votre aide, mais je l'ai compris. Voir ma réponse.



2
votes

La façon dont vous avez posé votre problème, il n'y a aucun moyen de le faire. iEnumerable est un extraire énumérable - c'est-à-dire que vous pouvez getenumerator à l'avant de la séquence puis demander à plusieurs reprises "donnez-moi le Article suivant "( MOVENNEXT / actuel ). Vous ne pouvez pas, sur un thread, avoir deux choses différentes de tirer de animaux.select (a => a.chickens) et animaux.select (a => a.goats) < / code> en même temps. Vous devriez faire l'un des autres (ce qui nécessiterait de matérialiser la seconde).

La suggestion Blueraja fabriquée est une façon de changer légèrement le problème. Je suggérerais d'aller cette route.

L'autre alternative consiste à utiliser iobservable à partir d'extensions réactives de Microsoft (RX), un poussoir énumérable . Je n'entrerai pas dans les détails de la façon dont vous feriez cela, mais c'est quelque chose que vous pourriez examiner.

EDIT:

Ce qui précède suppose que consommationchickens et consumesegoats sont tous deux renvoyés void ou ne renvoient au moins pas ienumerable < / Code> eux-mêmes - ce qui semble être une hypothèse évidente. J'apprécierais que si le bulletin de baisse boiteux commenterait réellement.


0 commentaires

1
votes

Je l'ai compris, merci en grande partie à cause du chemin que @lee m'a mis sur.

Vous devez partager un seul énumérateur entre les deux zips et utiliser une fonction adaptateur pour projeter le bon élément dans le Séquence. P>

private static IEnumerable<object> ConsumeChickens(IEnumerable<int> xList)
{
    foreach (var x in xList)
    {
        Console.WriteLine("X: " + x);
        yield return null;
    }
}

private static IEnumerable<object> ConsumeGoats(IEnumerable<int> yList)
{
    foreach (var y in yList)
    {
        Console.WriteLine("Y: " + y);
        yield return null;
    }
}

private static IEnumerable<int> SelectHelper(IEnumerator<AnimalCount> enumerator, int i)
{
    bool c = i != 0 || enumerator.MoveNext();
    while (c)
    {
        if (i == 0)
        {
            yield return enumerator.Current.Chickens;
            c = enumerator.MoveNext();
        }
        else
        {
            yield return enumerator.Current.Goats;
        }
    }
}

private static void Main(string[] args)
{
    var enumerator = GetAnimals().GetEnumerator();

    var chickensList = ConsumeChickens(SelectHelper(enumerator, 0));
    var goatsList = ConsumeGoats(SelectHelper(enumerator, 1));

    var temp = chickensList.Zip(goatsList, (i, i1) => (object) null);
    temp.ToList();

    Console.WriteLine("Total iterations: " + iterations);
}


5 commentaires

Je n'ai pas de contrôle sur la fonction source ou les deux fonctions de consommation. Je travaille sur la fabrication de cette plus jolie.


Cela repose sur le fait que énumérable.zip () appelle l'énumérateur de chaque séquence d'alternance, et que le deuxième énumérateur est appelé avant le premier. Aucun de ces faits n'est garanti par la documentation , ce qui signifie que cette solution peut ne fonctionne pas toujours, ou pourrait arrêter soudain de travailler dans une future version de .NET.


C'est correct. Cependant, j'ai vraiment besoin de consommer les objets comme des listes et non comme des objets individuels (par lots).


Si vous n'avez pas de contrôle sur les deux fonctions de consommation, comment les faites-vous retour de rendement après chaque entrée?


@Blueraja exactement le point de ma réponse, qui a été évité.



2
votes

Fait réellement simulaires de manière à réaliser ce que vous pouvez convertir la valeur de retour des fermiers à l'établissement pour pousser la collecte ou le fonctionnement iobservable et utiliser réactifextensions pour travailler avec celui-ci

var observable = new Subject<Animals>()
observable.Do(x=> DoSomethingWithChicken(x. Chickens))
observable.Do(x=> DoSomethingWithGoat(x.Goats))

foreach(var item in FarmsInEachPen())
{
    observable.OnNext(item)
}   


3 commentaires

Intéressant. Cela projetera ienumerable à ienumerable , ienumerable ou devrai-je modifier DOSOMEATHIPKEN / Chèvre à utiliser?


Si vous voulez le faire dans le flux comme un modèle (c'est-à-dire sans créer d'autres collections pour accumuler des éléments), vous devrez écrire une fonction qui accepte chaque élément séparément, mais il existe en fait des fonctions dans RX qui convertissent observables.


Ce dernier est ce que je serais intéressé. Je vais télécharger Rx et voir ce que je peux faire avec cela, je reviendrai cette question et changer la réponse acceptée si elle peut le faire.