2010-03-21 2 views
2

У меня есть массив определенного типа. Теперь я хочу найти запись, в которой выполняется определенное условие.Array.BinarySearch, где выполняется определенное условие

Каков предпочтительный способ сделать это с ограничением, что я не хочу создавать временный объект для поиска, но вместо этого хочу только задать условие поиска.

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

Возможно, возможно ли использовать LINQ для его решения?

EDIT: Я знаю, что он работает с обычными коллекциями, но мне нужно, чтобы он работал для BinarySearch.

ответ

3

Просто используйте FirstOrDefault (или SingleOrDefault, если оно уникально).

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

Или, если вы хотите, чтобы заставить BinarySearch и вы знаете, что массив отсортирован

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

где MyClassNameComparer является IComparer<MyClass> и сопоставляются на основе свойства имени.

Если вы не хотите какого-либо временного объекта, я предполагаю, что постоянная строка в порядке, иначе вы потеряны - тогда вы можете использовать.

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

Где MyClassOrStringComparer способен сравнить строку в объект MyClass (и наоборот).

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

первый из них не является бинарным. второй создает временный объект для поиска, который я не хочу создавать, как я сказал в вопросе. – codymanix

+0

Извините. Я неправильно понимаю ваш вопрос как не желающий создать временный массив. Я думаю, что ваше ограничение на создание временного объекта ошибочно, так как оно облегчает решение. В противном случае вам нужно создать более сложный компаратор, который может сравнивать объект MyClass с строкой. – tvanfosson

+0

@codymanix - note Я обновил свой ответ с помощью сопоставителя строки/MyClass, который, как я думаю, соответствует вашим требованиям, за исключением того, что использует временный строковый объект. :-) – tvanfosson

2

Нет, BinarySearch не содержит перегрузки с параметром <>. Вы можете использовать метод LINQ вместо:

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

это не бинарный поиск. – codymanix

1

BinarySearch может использоваться только тогда, когда массив отсортирован, и только при поиске конкретного значения ключа сортировки. Таким образом, это исключает использование произвольного предиката.

0

Вы можете использовать метод Comparer<T>.Create() помощника и закрытие для захвата целевого значения:

метода
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]; 

Этого помощник доступен, начиная с .NET Framework 4.5.

Помните, что если myArray содержит несколько элементов, удовлетворяющих данному условию, Array.BinarySearch() вернет элемент, который был найден первым. Это не обязательно элемент с минимальным индексом.

Смежные вопросы