2016-05-28 2 views
1

Если мы выполним следующие (благодаря @octavioccl за помощью) запросов LINQ:Найти Струны с некоторым Хэммингом расстоянием LINQ

var result = stringsList 
.GroupBy(s => s) 
    .Where(g => g.Count() > 1)   
    .OrderByDescending(g => g.Count()) 
    .Select(g => g.Key); 

Это дает нам все строки, которые имеют место в списке по крайней мере дважды (но точно совпадают, т. е. расстояние Хэмминга = 0).

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

P.S: Все строки имеют одинаковую длину

UPDATE

Действительно, благодаря krontogiannis за подробный ответ. Как я упоминал ранее, я хочу получить список строк с расстоянием от помех ниже заданного порога. Его код работает отлично для него (Еще раз спасибо).

Единственное оставшееся это взять строки из «результирующем» и вставить/добавить в `List»

В основном это то, что я хочу:

List<string> outputList = new List<string>(); 
foreach (string str in patternsList) 
      { 
       var rs = wordsList 
    .GroupBy(w => hamming(w, str)) 
    .Where(h => h.Key <= hammingThreshold) 
    .OrderByDescending(h => h.Key) 
    .Select(h => h.Count()); 
outputList.Add(rs); //I know it won't work but just to show what is needed 
      } 

Благодаря

+0

Хэмминга расстояние применим к строкам равной длины. Все ли строки одинаковой длины? –

+0

Если у вас есть строки A, B и C, а A - 1 вдали от B, а B - 1 от C, но A находится на расстоянии более 1 от C, как вы хотите их сгруппировать? то есть. если они были номерами, и вы хотите сгруппировать все номера, которые не превышают 1, и у вас есть номера 1, 2 и 3, какую группу (группы) вы хотели бы создать из этого? –

+0

@ LasseV.Karlsen Хорошая точка Лассе. Кронто отлично справился с этим ответом –

ответ

3

Расчет расстояния от помех между t горе строки с помощью LINQ можно сделать изящным образом:

Func<string, string, int> hamming = (s1, s2) => s1.Zip(s2, (l, r) => l - r == 0 ? 0 : 1).Sum(); 

Вы вопрос немного расплывчато о «группировке». Как вы можете видеть, чтобы рассчитать расстояние от хамминга, вам понадобятся две строки. Таким образом, вам нужно либо вычислить расстояние для хамминга для всех слов в списке строк по сравнению с входом, либо рассчитать расстояние между всеми для слов в вашем списке (или что-то другое, что вам нужно сказать нам :-)).

В любом случае я дам два примера для ввода

var words = new[] { 
    "hello", 
    "rellp", 
    "holla", 
    "fooba", 
    "hempd" 
}; 

Случай 1

var input = "hello"; 
var hammingThreshold = 3; 

var rs = words 
    .GroupBy(w => hamming(w, input)) 
    .Where(h => h.Key <= hammingThreshold) 
    .OrderByDescending(h => h.Key); 

Выходной будет что-то вроде

hempd with distance 3 
rellp holla with distance 2 
hello with distance 0 

Случай 2

var hs = words 
    .SelectMany((w1, i) => 
     words 
      .Where((w2, j) => i > j) 
      .Select(w2 => new { Word1 = w1, Word2 = w2 })) // all word pairs except with self 
    .GroupBy(pair => hamming(pair.Word1, pair.Word2)) 
    .Where(g => g.Key <= hammingThreshold) 
    .OrderByDescending(g => g.Key); 

Выходной будет что-то вроде

(holla, rellp) (fooba, holla) (hempd, hello) with distance 3 
(rellp, hello) (holla, hello) with distance 2 

Редактировать Чтобы получить только слова из первой группировки можно использовать SelectMany

var output = rs.SelectMany(g => g).ToList(); 
+0

Спасибо за ваш ответ. Огромное усилие! Действительно благодарен –

+0

У меня возникают трудности с выбором 'Select' для случая 1. Я хочу выбрать только строки. –

+0

Вы можете перебирать их для каждой группы, как я [здесь] (https://dotnetfiddle.net/ocAfbj). Или вы должны обновить свой ответ, чтобы дать немного больше информации о том, что вы пытаетесь сделать. – krontogiannis

-1

Вы могли бы сделать что-то вроде этого:

int hammingDistance = 2; 
var result = stringsList 
.GroupBy(s => s.Substring(0, s.Length - hammingDistance)) 
.Where(g => g.Count() > 1) 
.OrderbyDescending(g => g.Count()) 
.Select(g => g.Key);