2013-04-02 5 views
4

У меня есть массив строк в следующем формате, где каждая строка начинается с трех символов, указывающих, какой тип данных он содержит. Например:Разграничение данных для конкретного экземпляра повторяющейся строки

ABC | .....
DEF | ...
RHG | 1 ........
RHG | 2 ........
RHG | 3 ........
XDF | ......

Я хочу, чтобы найти какие-либо повторяющиеся строки (РГГ в данном примере) и отметьте последнюю строку с особым характером :

> RHG | 3 .........

Каков наилучший способ для этого? Мое текущее решение имеет метод подсчета заголовков строк и создания словаря с подсчетами заголовков.

protected Dictionary<string, int> CountHeaders(string[] lines) 
{ 
    Dictionary<string, int> headerCounts = new Dictionary<string, int>(); 
    for (int i = 0; i < lines.Length; i++) 
    { 
     string s = lines[i].Substring(0, 3); 

     int value; 
     if (headerCounts.TryGetValue(s, out value)) 
      headerCounts[s]++; 
     else 
      headerCounts.Add(s, 1); 
    } 
    return headerCounts; 
} 

В основном методе синтаксического анализа я выбираю строки, которые повторяются.

var repeats = CountHeaders(lines).Where(x => x.Value > 1).Select(x => x.Key); 
foreach (string s in repeats) 
{ 
    // Get last instance of line in lines and mark it 
} 

Это все, что я получил. Я думаю, что могу сделать то, что хочу, с другим запросом LINQ, но я не уверен. Кроме того, я не могу не чувствовать, что есть более оптимальное решение.

ответ

4

Вы можете использовать LINQ для достижения этой цели.

Входная строка:

var input = @"ABC|..... 
DEF|... 
RHG|1........ 
RHG|2........ 
RHG|3........ 
XDF|......"; 

LINQ запрос:

var results = input.Split(new[] { Environment.NewLine }) 
        .GroupBy(x => x.Substring(0, 3)) 
        .Select(g => g.ToList()) 
        .SelectMany(g => g.Count > 1 ? g.Take(g.Count - 1).Concat(new[] { string.Format(">{0}", g[g.Count - 1]) }) : g) 
        .ToArray(); 

Я использовал Select(g => g.ToList()) проекции, чтобы сделать g.CountO (1) операции в дальнейших шагах запроса.

Вы можете Join результат массива в одну строку с помощью метода String.Join:

var output = String.Join(Environment.NewLine, results); 
+0

+1, спасибо за заметки, я не вижу смысла делать свой ответ таким же, как ваш. –

+0

Wow thanks, не знаю, я мог бы сделать все в одном запросе LINQ! – Otaia

+0

@ Otaia LINQ - действительно мощный инструмент. Вы просто должны знать, как его использовать. – MarcinJuraszek

0

Вот пример, который включает в себя синтаксический анализ и подсчет в одном заявлении Linq - не стесняйтесь, чтобы разбить его, если вы хотите:

string[] data = new string[] 
{ 
    "ABC|.....", 
    "DEF|...", 
    "RHG|1........", 
    "RHG|2........", 
    "RHG|3........", 
    "XDF|......" 
}; 

data.Select(d=> d.Split('|'))      // split the strings 
    .Select(d=> new { Key = d[0], Value = d[1] }) // select the key and value 
    .GroupBy (d => d.Key)       // group by the key 
    .Where(g=>g.Count() > 1)      // find duplicates 
    .Select(d => d.Skip(1))      // select the repeating elements 
    .SelectMany(g=>g)        // flatten into a single list 
    ;      

Это даст вам список пар ключ/значение, которые дубликаты. так с данными выборки будет возвращать

Key Value 
RHG 2........ 
RHG 3........ 

Я не уверен, что вы имеете в виду под «маркировки» линии, однако ...

+0

«и отметьте последнюю строку специальным символом» –

1

В качестве альтернативы, вы можете найти повторяющиеся строки с регулярным выражением ссылочность. Я написал это хакерское регулярное выражение, используя ваши данные образца, и он соответствует строкам, начинающимся с предшествующего «тега», разделенных по каналам значений.

^(?<Tag>.+)[|].+[\n\r](\k<Tag>[|].+[\n\r])+ 

Диапазон совпадений начинается в начале первой линии RHG и выбирается до последней линии RHG.

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