2010-03-21 6 views
2

J'ai un tableau d'un certain type. Maintenant, je veux trouver une entrée où une certaine condition est remplie.Array.BinarySearch où une certaine condition est remplie

Quelle est la manière préférée de le faire avec la restriction que je ne veux pas créer un objet temporaire à trouver, mais je veux seulement donner une condition de recherche.

MyClass[] myArray; 
// fill and sort array.. 
MyClass item = Array.BinarySearch(myArray, x=>x.Name=="Joe"); // is this possible? 

Peut-être est-il possible d'utiliser LINQ pour le résoudre? Je sais que cela fonctionne sur les collections normales, mais j'en ai besoin pour travailler avec BinarySearch. Il suffit d'utiliser FirstOrDefault (ou SingleOrDefault, si unique)

Répondre

3

var myItem = myArray.FirstOrDefault(x => x.Name == "Joe"); 

Ou si vous voulez forcer un BinarySearch et vous savez que le tableau est trié

var myItem = Array.BinarySearch(myArray, 
            new MyClass { Name = "Joe" }, 
            new MyClassNameComparer()); 

où MyClassNameComparer est IComparer<MyClass> et compare basée sur la propriété du nom.

Si vous ne voulez aucun objet temporaire - je suppose qu'une chaîne constante est ok, sinon vous êtes perdu - alors vous pouvez utiliser.

var myItem = Array.BinarySearch(myArray, 
            "Joe", 
            MyClassOrStringComparer()); 

Où MyClassOrStringComparer est capable de comparer une chaîne à un objet MyClass (et vice versa).

public class MyClassOrStringComparer 
{ 
    public int Compare(object a, object b) 
    { 
     if (object.Equals(a,b)) 
     { 
      return 0; 
     } 
     else if (a == null) 
     { 
      return -1; 
     } 
     else if (b == null) 
     { 
      return 1; 
     } 

     string aName = null; 
     string bName = null; 

     if (a is string) 
     { 
      aName = a; 
     } 
     else 
     { 
      aName = ((MyClass)a).Name; 
     } 

     if (b is string) 
     { 
      bName = b; 
     } 
     else 
     { 
      bName = ((MyClass)b).Name; 
     } 

     return aName.CompareTo(b.Name); 
    } 
+1

le premier n'est pas binarysearch. le second crée un objet temporaire à trouver que je ne veux pas créer, comme je l'ai dit dans la question. – codymanix

+0

Désolé. J'ai mal interprété votre question comme ne voulant pas créer un tableau temporaire. Je pense que votre restriction de ne pas créer un objet temporaire est erronée car elle facilite la solution. Sinon, vous devez créer un comparateur plus complexe qui peut comparer un objet MyClass à une chaîne. – tvanfosson

+0

@codymanix - note J'ai mis à jour ma réponse avec une chaîne/un comparateur MyClass qui, je pense, répond à vos besoins - sauf qu'il utilise un objet chaîne temporaire. :-) – tvanfosson

2

Non, BinarySearch ne contient pas de surcharge avec Comparaison <> parameter. Vous pouvez utiliser la méthode LINQ à la place:

MyClass item = myArray.FirstOrDefault(x => x.Name == "Joe"); 
+5

ce n'est pas binarysearch. – codymanix

1

BinarySearch ne peut être utilisé lorsque le tableau est trié, et uniquement lorsque la recherche d'une valeur particulière de la clé de tri. Cela exclut donc l'utilisation d'un prédicat arbitraire.

0

Vous pouvez utiliser la méthode d'aide Comparer<T>.Create() et une fermeture pour capturer la valeur cible:

int i = Array.BinarySearch(myArray, null, Comparer<MyClass>.Create((item, _) => string.Compare(item.Name, "Joe", StringComparison.Ordinal))); 
if (i < 0) 
    // Complain. 
MyClass item = myArray[i]; 

Cette méthode d'assistance est disponible depuis .NET Framework 4.5.

Sachez que si myArray contient plusieurs éléments qui répondent à des conditions données, Array.BinarySearch() renverra un élément qu'il fonde en premier. Ce qui n'est pas nécessairement un élément qui a un indice minimum.

Questions connexes