2016-11-17 1 views
1

J'ai fait une fonction pour générer les nombres impairs:Filtre sur IEnumerable ... .Où?

static IEnumerable<int> OddNumbers() 
{ 
    int n = 1; 
    while (true) 
    yield return 1 + 2 * (n++ - 1); 
} 

Comment puis-je aller à travers et filtrer cette liste? Je suis en train de supprimer tous les multiples d'un certain nombre factor, je l'ai écrit ceci:

using (var oddNumbers = OddNumbers().GetEnumerator()) 
{ 
    oddNumbers.MoveNext(); 
    int factor = oddNumbers.Current; 

    yield return factor; 
    oddNumbers = oddNumbers.Where(x => x % factor != 0); 
} 

mais on me dit que

The type arguments for method `System.Linq.Enumerable.Where<TSource>(
    this System.Collections.Generic.IEnumerable<TSource>, 
    System.Func<TSource,bool>)' cannot be inferred from the usage. 
Try specifying the type arguments explicitly` 
+0

Declare 'oddNumbers' comme:' IEnumerable oddNumbers = OddNumbers(); '. Ensuite, utilisez une autre variable dans 'using 'pour l'énumérateur. –

+0

'oddNumbers' est un' IEnumerator 'mais' Where' nécessite un 'IEnumerable '. Vous pouvez simplement utiliser 'OddNumbers(). Où (x => x% factor! = 0)'. – Lee

+0

Euh ... toutes ces opérations semblent scary infinies ... – Nyerguds

Répondre

3

À ma connaissance il n'y a pas besoin d'accéder directement au recenseur, cela peut être fait en utilisant Linq seul comme suit.

var FilteredNumbers = OddNumbers().Where(x => x % factor != 0); 
+2

Cependant, assurez-vous d'appliquer une protection sur l'énumérable, par ex. Take(), pour empêcher une boucle infinie si plus tard vous parcourez la collection complète: foreach, .ToList(). etc ... – LeBaptiste

+0

Je filtre à plusieurs reprises la collection, et j'aimerais que le filtre suivant utilise la sortie du précédent. Existe-t-il un moyen de filtrer la collection sur place et de stocker le résultat? Prêt à être filtré à nouveau? – theonlygusti

1

Vous pouvez utiliser Linq:

// Initial generator 
    static IEnumerable<int> OddNumbers() { 
    for (int n = 1; ; n += 2) // for loop is far better than while here 
     yield return n; 
    } 

    ... 

    var result = OddNumbers() 
    .Where(x => x % factor ! = 0); 

Ou modifier le générateur lui-même:

static IEnumerable<int> OddNumbersAdvanced(int factorToExclude = int.MinValue) { 
    for (int n = 1; ; n += 2) 
     if (n % factorToExclude != 0) 
      yield return n; 
    } 

    ... 

    var result = OddNumbersAdvanced(factor); 

passer par la boucle utilisation foreach:

foreach (int item in result) { 
    //TODO: put relevant code here; do not forget to break the loop 
    } 
+0

Je filtre à plusieurs reprises la collection et je voudrais que le filtre suivant utilise la sortie du précédent. Existe-t-il un moyen de filtrer la collection sur place et de stocker le résultat? Prêt à être filtré à nouveau? – theonlygusti

+0

Vous pouvez * empiler * les filtres: 'var result = OddNumbers(). Où (item => élément% factor! = 0) .Where (item => élément <100000) .Where (item => (item * item)% 5 == 1); 'il suffit de mettre autant de' Where' sont nécessaires –

+0

infiniment beaucoup ...... bien sûr que je fais juste cela – theonlygusti

0

Puisque vous en avez besoin pour générer une séquence de nombres chanceux, voici un code que j'ai écrit pour faire cela avec les itérateurs. Notez qu'il est très inefficace de le faire de cette façon, mais nous espérons que vous faites cela juste pour le plaisir ou pour apprendre

static IEnumerable<int> LuckyNumbers(IEnumerable<int> all = null, int n = 2, int step = 0) { 
    if (step == 0) { 
     all = Enumerable.Range(1, int.MaxValue); // start with all numbers 
     yield return 1; 
     step++; 
    }    
    // apply a filter for current "n" (starting with 2) 
    var filtered = Filtered(all, n); 
    // get next item from the sequence (skip items first, because this sequence represents whole lucky number sequence, starting from 1) 
    var current = filtered.Skip(step).First(); 
    yield return current; 
    step++; 
    // now recursive call back into LuckyNumber 
    foreach (var other in LuckyNumbers(filtered, current, step)) { 
     yield return other; 
    } 
} 

static IEnumerable<int> Filtered(IEnumerable<int> previous, int n) { 
    // filter out each n-th item 
    return previous.Where((x, i) => (i + 1)%n != 0); 
} 

Utilisez comme ceci:

foreach (var next in LuckyNumbers().Take(10)) { 
    Console.WriteLine(next); 
} 
+0

Vous me dites "qui n'est pas liée à la divisibilité par X (donc, pas lié au facteur x%)" Pourtant, je vois dans votre propre réponse: "Où ((x, i) => (i + 1)% n ! = 0); " – theonlygusti

+0

@theonlygusti Eh bien dans ma réponse je ne divise pas x, mais je (index de l'article dans une séquence, pas le nombre lui-même). – Evk

+0

Je le fais dans ma solution la plus récente. J'ai fait une erreur dans la question. – theonlygusti