GQ08 V: révisons les ensembles


Voici un cinquième quizz pour le week-end. Soupçonnant une semaine de 15 août un peu désertée je reprendrai plus activement les quizzs la semaine prochaine.

Je vous propose ici de rechercher la liste distincte des caractères présents dans l’ensemble des chaînes de caractères.

Puis dans une second temps, l’ensemble des caractères présents dans toutes les chaînes de caractères.

Petite option: exclure les espaces.

var names = new string[] { "Mitsuru FURUTA", "Dick LANTIM", "Pierre LAGARDE" }; ? //All dictincts chars foreach (var c in?) Console.WriteLine(c); //Chars common to all strings foreach (var c in?) Console.WriteLine(c);

image

Comments (15)

  1. c.Yoann says:

    Je propose :

    //All dictincts chars

    var dc = (from name in names

         from ch in name

         where ch != ‘ ‘

         select char.ToUpper(ch)).Distinct();

    //Chars common to all strings

    var cc = (from name in names

         from ch in name

         where ch != ‘ ‘ && names.All(s => s.ToUpper().Contains(char.ToUpper(ch)))

         select char.ToUpper(ch)).Distinct();

    Si on ne devait utiliser que des fonctionnelles, on pourrait remplacer le Contains (dans cc) par un Any(…). Mais ça rallonge un petit peux ma solution !

  2. Mitsu Furuta says:

    Well done !

    Pour la seconde requête (common chars), ta solution est un peu couteuse. En effet tu as deux boucles imbriquées qui parcourent names, dans le ‘from’ et dans ‘names.All()’. On peut optimiser cette algo.

    Je commenterai plus tard la première requête.

  3. Miiitch says:

    Voici pour moi:

    var q1 = (from name in names

            from c in name.ToUpper()

            where Char.IsLetter(c)

            select c).Distinct();

    et:

    var q2 = (from name in names

             from c in name.Distinct()

             where Char.IsLetter(c)

             group name by c into gp

             where gp.Count() == 3

             select gp.Key);

    Un détail: Distinct() c’est pas proposé par intellisence pour le name.Distinct(): tout ça pour que personne ne sache qu’une string c’est un IEnumerable<char> !! 🙂

    Michel

  4. Miiitch says:

    Une petite coquille sur la fin corrigée:

    var q2 = (from name in names          

             from c in name.Distinct()

             where Char.IsLetter(c)

             group name by c into gp

             where gp.Count() == names.Count()

             select gp.Key);

    Michel

  5. Olivier says:

    j’ai ça pour la première partie :

    var q = (from s in names

                        select s.ToUpper().ToCharArray()

                        into d

                            from c in d

                            where c!=’ ‘

                            select c).Distinct();

    pour la seconde je cherche encore.

  6. Olivier says:

    Une solution pour le second point qui utilise les opérateurs ensemblistes de Linq. Mais ça ne me satisfait pas vraiment:

    var cs = names[0].ToCharArray();

    foreach (var s in names)

         cs =(cs.Intersect(s.ToCharArray())).ToArray();

    foreach (var c in cs) Console.WriteLine(c);

    Je coince sur le moyen, en une seule requête Linq, de faire justement l’Intersect de toutes les chaînes, sans le foreach.

  7. Nico says:

    La première, plus old school :

    var unique = string.Join("", names).ToUpper().Distinct();

  8. Pour ma part, je propose ça :

    var q1 = names.SelectMany(n => n.ToUpper()).Where(c => c != ‘ ‘).Distinct();

    var q2 = names.Select(n => (IEnumerable<char>)n.Replace(" ", "")).Aggregate((a, b) => a.Intersect(b));

  9. Après réflection, je pense que ce Replace n’est pas idéal. Autant faire ceci :

    var q2 = names.Select(n => (IEnumerable<char>)n).Aggregate((a, b) => a.Intersect(b)).Where(c => c != ‘ ‘);

    Ou alors en version plus fun mais plus longue mais plus réutilisable :

    public class ComparerWithForbiddenValues<T> : IEqualityComparer<T>

    {

       private IEqualityComparer<T> _equalityComparer;

       private IEnumerable<T> _forbiddenValues;

       public ComparerWithForbiddenValues()

       {

       }

       public ComparerWithForbiddenValues(IEqualityComparer<T> equalityComparer)

       {

           _equalityComparer = equalityComparer;

       }

       public IEnumerable<T> ForbiddenValues

       {

           get { return _forbiddenValues; }

           set { _forbiddenValues = value; }

       }

       public bool Equals(T x, T y)

       {

           if (_equalityComparer == null)

               return ! _forbiddenValues.Any(v => v.Equals(x) || v.Equals(y)) && x.Equals(y);

           return ! _forbiddenValues.Any(v => _equalityComparer.Equals(v, x) || _equalityComparer.Equals(v, y)) && _equalityComparer.Equals(x, y);

       }

       public int GetHashCode(T obj)

       {

           if (_equalityComparer == null)

               return obj.GetHashCode();

           return _equalityComparer.GetHashCode(obj);

       }

    }

    puis

    var q2 = names.Select(n => (IEnumerable<char>)n).Aggregate((a, b) => a.Intersect(b, new ComparerWithForbiddenValues<char> { ForbiddenValues = new char[] { ‘ ‘ } })).Where(c => c != ‘ ‘);

  10. Mitsu says:

    Matthieu, on avait dit qu’une seule réponse pour toi 🙂

    C’est pas pour te limiter, c’est pour que tu prennes ton temps avant de poster.. mais visiblement c’est trop dur ! lol

  11. Miiitch says:

    Le mieux c’est de le bannir du blog 🙂

  12. Attend, j’étais déjà assez frustré comme ça de voir qu’il y avait un nouveau quizz et que, n’ayant pas allumé mon pc des 3 derniers jours, je n’étais pas le premier à répondre. lol

  13. Ce quizz est un peu spécial car il est inclut dans "un vrai post". Où placer le where ? Cette question

  14. Réponse au quizz précédent. Ce quizz va me permettre de rappeler plusieurs points intéressants: – Jouer