2009-06-29 7 views
1

J'espère que le titre a du sens.Effectuer une recherche booléenne AND string sur les sous-collections d'une collection (non-LINQ)

J'ai un ensemble de items que je veux rechercher et sélectionner un sous-ensemble, sur la base d'un ensemble de keywords qui doit apparaître tout au moins une fois dans l'un des SubItems des Item s. Je crois que cela pourrait facilement être réalisé en utilisant LINQ, mais j'utilise .NET 2.0 pour ce projet.

Le code ci-dessous devrait réaliser à peu près ce que je veux faire, en supposant que AllBitsAreSet est mis en œuvre, mais je me demande s'il me manque une alternative, une façon plus simple de le faire?

Puisqu'il ne semble pas y avoir un bon moyen de vérifier si tous les bits d'un BitArray sont définis, en plus de les boucler tous (s'il vous plaît dites-moi s'il y en a!), Je m'interroge sur "plus agréable" alternatives. Pas nécessairement plus efficace CPU, car je doute que le code ci-dessous sera trop lent pour les jeux de données avec lesquels je travaille, mais ceux avec moins de code.

public List<Item> Search(Item[] items, List<string> keywords) 
{ 
    List<Item> results = new List<Item>(); 

    BitArray flags = new BitArray(keywords.Count); 
    foreach (Item item in items) 
    { 
     flags.SetAll(false); 
     foreach (SubItem subItem in item.SubItems) 
     { 
      for (int i = 0; i < keywords.Count; i++) 
      { 
       if (subItem.StringValue.IndexOf(keywords[i]) >= 0) 
        flags[i] = true; 
      } 
     } 
     if (AllBitsAreSet(flags)) results.Add(item); 
    } 

    return results; 
} 
+0

Combien de sous-éléments d'un élément peut avoir? La boucle interne (pour int i = 0) me semble être un problème. – shahkalpesh

+0

Il vaudra mieux que vous fournissiez une entrée d'échantillon/une sortie attendue. – shahkalpesh

Répondre

3

Vous pouvez utiliser LINQ Bridge pour obtenir un soutien LINQ sur .NET 2.0 et utilisez la requête LINQ suivante.

items.Where(i => 
    keywords.All(k => 
     i.SubItems.Any(s => 
      s.StringValue.Contains(k)))); 

Vous pouvez éviter d'utiliser le bit défini si vous échangez les deux boucles internes - l'impact de la performance dépend thenumber des points de sous vs le nombre de mots-clés.

foreach (Item item in items) 
{ 
    Boolean found = false; 

    foreach (String keyword in keywords) 
    { 
     found = false; 

     foreach (SubItem subItem in item.SubItems) 
     { 
      if (subItem.StringValue.Contains(keyword)) 
      { 
       found = true; 
       break; 
      } 
     } 

     if (!found) 
     { 
      break; 
     } 
    } 

    if (found) 
    { 
     result.Add(item); 
    } 
} 
+0

Ah, bien sûr =) Merci! – Blixt

0

Je l'écrirais comme suit. Bien sûr, c'est très similaire à la solution de Daniel, mais je crois que c'est mieux.

public List<Item> Search(Item[] items, List<string> keywords) 
    { 
     List<Item> results = new List<Item>(); 
     foreach (Item item in items) 
      if(ContainsAllKeywords(item, keywords)) 
       results.Add(item); 
     return results; 
    } 

    bool ContainsAllKeywords(Item item, List<string> keywords) 
    { 
     foreach (string keyword in keywords) 
      if (!ContainsKey(item.SubItems, keyword)) 
       return false; 
     return true; 
    } 

    bool ContainsKey(IEnumerable<SubItem> subItems, string key) 
    { 
     foreach (SubItem subItem in subItems) 
      if (subItem.StringValue.Contains(key)) 
       return true; 
     return false; 
    } 

modifier: changé ==-.Contains() comme par commentaire

+0

Votre code n'a pas les mêmes fonctionnalités que Blixt's et Daniel's. Votre code vérifie une correspondance exacte entre subItem.StringValue et chaque mot clé. Il devrait vérifier pour une correspondance de sous-chaîne. – LukeH

+0

Si une correspondance exacte était permise, de meilleures optimisations seraient disponibles. Par exemple, vous pouvez stocker les mots-clés en tant que clés dans un dictionnaire (ou utiliser un HashSet dans les versions ultérieures de .NET), ce qui donnera le temps de recherche O (1). – LukeH

+0

Luke, oui c'était une erreur cela aurait dû être .Contains() au lieu de ==. Merci d'avoir attrapé ça! J'ai modifié le code. Cependant, je ne suis pas d'accord avec votre évaluation sur l'utilisation d'un dictionnaire/hachage. Je comprends que la recherche de hachage est O (1), mais je ne vois pas comment cela peut être directement appliqué pour améliorer les performances dans cette situation. Pourriez-vous s'il vous plaît fournir un échantillon de code? Merci pour les commentaires. – dss539

Questions connexes