2011-12-19 3 views
5

Скажите, что у меня есть элементы (X, Y и Z) в списке, у меня есть функция, которая генерирует процент, из которых два объекта похожи друг на друга.Как выполнить функцию сравнения в C#

То, что я хочу сделать, это запустить X против Y и Z, используя мои compareElements, так:

compareElements(X,Y); // equals 55 
compareElements(X,Z); // equals 60 

Тогда Y против X и Z

compareElements(Y,X); // equals 55 
compareElements(Y,Z); // equals 62 

Тогда Z против Y и X

compareElements(Z,X); // equals 60 
compareElements(Z,Y); // equals 62 

Затем я вернусь наибольшее значение, которое 62.

Очевидно, что там есть повторение, мне не нужно повторение, но я не уверен, как его устранить.

Как структурировать мой запрос LINQ или функцию/алгоритм для этого сравнения для каждого элемента без повторения?

Я бы предпочел использовать LINQ, если смогу, поскольку мне передают перечислимое значение, и функция возвращается до того, как список фактически перечислит, поэтому мы можем сэкономить стоимость выполнения сравнения, пока список не будет перечислен ,

Все, что мне нужно, что наибольшее значение, из сравнить функции 62.

Примечание: Мой фактический набор результатов я работаю со средними значениями от 3 до 10 элементов в списке, что нужно быть побежал через эту функцию сравнения.

+0

У вас есть список > или аналогичный? или как у вас есть элементы X, Y, Z? –

+0

Вам также нужно знать, какой из двух объектов привел к наибольшему значению? –

+0

Если вам нужен только самый высокий элемент, не можете ли вы просто использовать List.Sort(). Last()? –

ответ

2

Ради удобства чтения, я хотел бы написать блок итератора для генерации сравнения в не-повторяющимся образом:

IEnumerable<Tuple<T, T>> GetComparisons<T>(IEnumerable<T> elements) 
{ 
    var visited = new List<T>(); 

    foreach(T current in elements) 
    { 
     foreach(T previous in visited) 
      yield return new Tuple<T, T>(current, previous); 

     visited.Add(current); 
    } 
} 

Затем вы можете сделать следующее:

var highScore = GetComparisons(listOfElements) 
        .Select(x=>compareElements(x.Item1, x.Item2) 
        .Max(); 

(Это сказал, что я предпочитаю предложение Smelch для ситуаций, когда нет практических оснований для использования LINQ или итераторов, таких как необходимость в составных подпрограммах.)

+0

Ваше решение получило неплохую работу для меня и клиента! GetComparisons - это действительно хорошая идея! –

5

Я не уверен, что я правильно понять вас, но попробовать что-то вроде этого:

public int compareElementList(List<Element> elements) 
    { 
     int result = 0; 
     for (int i = 0; i < elements.Count - 1; i++) 
     { 
      for (int q = i + 1; q < elements.Count; q++) 
      { 
       result = Math.Max(result, compareElements(elements[i], elements[q])); 
      } 
     } 

     return result; 
    } 

Это позволит устранить дублирующие сравнения для вас. Он не использует LINQ, но я думаю, что он все еще довольно читабельен.

UPDATE: Здесь моя версия модифицирована для обработки IEnumerables. Он варьируется от Джона Ханны в том, что он не создает новый список, он просто отслеживает два итератора.

public int compareElementEnumerable(IEnumerable<Element> elements) 
    { 
     int result = 0, i = 0, q = 1; 
     foreach (Element el in elements) 
     { 
      foreach (Element el2 in elements) 
      { 
       if (q > i) 
       { 
        result = Math.Max(result, compareElements(el, el2)); 
       } 
       q++; 
      } 
      i++; 
     } 

     return result; 
    } 
+0

Кажется, довольно пятно-на. LINQ - инструмент, и если кто-то с кучей молотков спросил, как положить гвозди в вещи, тогда нет смысла показывать, как использовать отвертку, даже если они сказали, что хотели бы использовать его. –

+1

Это может также оказаться более эффективным. Я подозреваю, что любой метод, который использует LINQ, либо дублирует много сравнений, либо генерирует много промежуточных объектов. –

+0

@SeanU проблема в том, что мне передается IEnumerable, мне пришлось бы сначала передать это в список или массив? Разве это не так дорого? –

2

Вы могли бы составить список возможных комбинаций, которые вы хотите проверить в List<Tuple<int, int>> , а затем выбрать максимальную

mylist.Select(i => new [] { Tuple.New(i.X, i.Y}, Tuple.New(i.X, i.Z), Tuple.New(i.Y, i.Z)}) 
     .Max(t => compareElements(t.First, t.Second)) 
+0

, который работает, но мне все же приходится сначала составлять список –

+0

Будет ли это работать с вашей моделью? –

0

нечитаемой реализацию LINQ (не обобщать, я не проверял):

Enumerable.Range(0, listOfElements.Length).ToList().ForEach(i=>Enumerable.Range(i, listOfElements.Length-i-1).ToList().ForEach(j=>compareElements(listOfElements[i], listOfElements[j]))).Max(); 
2

не знаю, если это то, что вы ищете, но я хотел бы попробовать использовать LINQ следующим образом:

Пример реализации
var linq = from el1 in list 
      from el2 in list 
      where el1 != el2 
      select CompareFunction(el1, el2); 

int max = linq.Max(); 

Сравнение:

int CompareFunction(string a, string b) 
{ 
    return a.Length - b.Length; 
} 

Таким образом сравнить каждый элемент от других элементов в списке (это своего рода перестановки я думаю), кроме себя, а затем выберите значение сравнения и, наконец, наивысшее значение.

+0

Разве это еще не повторило бы сравнения? Если список содержит пункты 1, 2, 3; он будет сравнивать 1-2, затем 1-3, затем 2-1, 2-3, наконец 3-1 и 3-2. 1-2 является дубликатом 2-1, 1-3 является дубликатом 3-1 и 2-3 является дубликатом 3-2. – comecme

+0

Я думал об этом, но он не решает проблему, что он будет запускать повторяющийся код. –

8

Я был бы склонен делать это нравится:

int count = list.Count; 
var query = from index1 in Enumerable.Range(0, count) 
      from index2 in Enumerable.Range(index1 + 1, count - (index1 + 1)) 
      select ComputeSimilarity(list[index1], list[index2]); 
var maxSimilarity = query.Max(); 
1

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

List<Element> soFar = new List<Element>(); 
// If I expected a good few duplicate values, and if 
// compareElements(x, x) isn't 100% - i.e. it's not a similarity 
// check for example, then I'd use HashSet<Element> and skip 
// when .Add() fails. 

int result = 0; 
foreach(Element el in sourceEnumeration) 
{ 
    for(int i = 0; i != soFar.Count; ++i) 
    { 
    int cmp = compareElements(el, soFar[i]); 
    if(cmp > result) 
    { 
     if(cmp == 100) 
     return 100; 
     cmp = result; 
    } 
    } 
    soFar.Add(el); 
} 
return result; 
Смежные вопросы