Добавление и Couting элементов в списке - PullRequest
0 голосов
/ 10 августа 2011

Допустим, у меня есть файл, который выглядит следующим образом:

R34     128590    -74.498   109.728  0    0805_7  
R33     128590    -74.498   112.014  0    0805_7  
R15     128588    -68.910   127.254  0    0805_7  
R32     128587    -65.354   115.189  0    0805_7  
R35     128587    -65.354   117.348  0    0805_7  
R38     128590    -65.354   119.507  0    0805_7  

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

Есть ли способ сделать это с помощью списка?Если да, то как я могу это сделать?

Я пытался возиться с вещами, и вот куда я направлялся ... но это не работает должным образом

int lineCount = 1;
int itemCounter = 0;

foreach (var item in aListBox.Items)
{
    // Creates a string of the items in the ListBox.
    var newItems = item.ToString();

    // Replaces any multiple spaces (tabs) with a single space.
    newItems = Regex.Replace(newItems, @"\s+", " ");

    // Splits each line by spaces.
    var eachItem = newItems.Split(' ');

    ### 
    ### HERE is where I need help ###
    ### 
    List<string> partList = new List<string>();

    partList.Add(eachItem[1]);
    if (partList.Contains(eachItem[1]))
        itemCounter++;
    else 
        partList.Add(eachItem[1]);

    sw.WriteLine(lineCount + ": "+ partList + ": " + itemCounter);
    lineCount++;
}

SO для приведенного выше примера он вывел бы следующее:

1: 128590: 3        #lineCount, partList, itemCounter
2: 128588: 1
3: 128587: 2

Может кто-нибудь помочь мне понять, как это правильно сделать?

Ответы [ 6 ]

4 голосов
/ 10 августа 2011

используйте linq с счетчиком и группируйте по (см. Раздел «Сгруппированный счетчик»).

создайте partList вне цикла foreach и добавьте в него каждый элемент внутри цикла, чтобы он содержал все элементы:

List<string> partList = new List<string>();
foreach (var item in aListBox.Items)
{
    //regex stuff here...
    partList.Add(eachItem[1]);
} 

(в вашем примере- {128590, 128590, 128588, 128587, 128587, 128590})
и затем использовать LINQ для вывода результата-

var elementsWithCounts = from p in partList
     group p by p into g
     select new { Item = g.Key, Count = g.Count()};
2 голосов
/ 10 августа 2011

Я бы использовал запрос Linq или словарь

что-то вроде

    List<string> items = new List<string>{"128590", "128590", "128588", "128587", "128587", "128590"};
    Dictionary<string,int> result = new Dictionary<string,int>();

    foreach( int item in items )
    {
        if(result.ContainsKey(item) )
            result[item]++;
        else
            result.Add(item,1);
    }

    foreach( var item in result )
        Console.Out.WriteLine( item.Key + ":" + item.Value );
1 голос
/ 10 августа 2011

По сути, вы пытаетесь сделать это путем итерации один раз, и это на самом деле не сработает, вам придется выполнять итерацию дважды, в противном случае вы будете выполнять вывод каждый раз, когда выполняете цикл в foreach, идаже если вы точны, вы будете выводить новую строку каждый раз.Если вам действительно нужно использовать список вместо словаря с ключами или хеш-таблицы, который был бы идеальным для этого (ключ = число, значение = счетчик), то сначала нужно построить список, а затем обобщить список.Вы можете использовать LINQ Group By (что немного кратко) или создать функцию, которая делает что-то похожее на то, что у вас уже есть.Если вы пытаетесь изучить концепции, посмотрите на приведенный ниже код, он может быть более сжатым, но его должно быть довольно легко прочитать.

List<string> partList = new List<string>();
List<string> displayedNumbers = new List<int>();

// Build the original list first.
foreach (var item in aListBox.Items)
{
    // Creates a string of the items in the ListBox.
    var newItems = item.ToString();

    // Replaces any multiple spaces (tabs) with a single space.
    newItems = Regex.Replace(newItems, @"\s+", " ");

    // Splits each line by spaces.
    var eachItem = newItems.Split(' ');

    partList.Add(eachItem[1]);
}

// Now run through that list and count how many times the same number occurs.
// You will need two loops for this since your list is a single dimension collection.
foreach(var number in partList)
{
  var innerList = partList;


  // set this to zero because we are going to find at least 1 duplicate.
  var count = 0;

  foreach(var additionalNumber in innerList)
  {
    if(additionalNumber == number)
     {
       // If we find anymore increase the count each time.
       count += 1;
     }
  }  

   // Now we have the full count of duplicates of the outer number in the list.
   // If it has NOT been displayed, display it.
   if(!displayedNumbers.Contains(number))
    { 
      sw.WriteLine(partList + ": " + count);
      displayedNumbers.Add(number);
    }

}
1 голос
/ 10 августа 2011

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

[0] = "R34"
[1] = "128590"
[2] = "-74.498"
[3] = "109.728"
[4] = "0"
[5] = "0805_7"

Вы можете просто выполнить эту операцию с помощью операции Group By.

var items = aListBox.Items.Select(x => /* Split Code Here and Take Element 1 */).GroupBy(x => x);

foreach(var set in items)
{
     Console.WriteLine(set.Key + " appeared " + set.Count() + " times.");
}
0 голосов
/ 10 августа 2011

Я думаю, что самая большая проблема заключается в переходе от необработанных строк вашего текстового поля к отдельным значениям.Я предполагаю, что это файл с разделителями табуляции с известным постоянным числом столбцов, и в этом случае вы можете использовать String.Split () для разделения подстрок.После разделения строк вы можете легко подсчитать количество экземпляров соответствующего столбца с помощью небольшого LINQ.Имеется список или коллекция строк вашего файла:

var histogram = myListOfLines
    //Split each string along spaces or tabs, and discard any zero-length strings
    //caused by multiple adjacent delimiters.
   .Select(s=>s.Split(new[]{'\t',' '}, StringSplitOptions.RemoveEmptyEntries))
    //Optional; turn the array of strings produced by Split() into an anonymous type
   .Select(a=>new{Col1=a[0], Col2=a[1], Col3=a[2], Col4=a[3], Col5=a[4]})
    //Group based on the values of the second column.
   .GroupBy(x=>x.Col2)
    //Then, out of the grouped collection, get the count for each unique value of Col2.
   .Select(gx=>new{gx.Key, gx.Count()});
0 голосов
/ 10 августа 2011

Используйте хеш-таблицу вместо списка.Вы можете сохранить ключ как 128590, ... и значение, сколько раз он встречался.Перед тем как вставить новое значение, проверьте, присутствует ли оно в хеш-таблице, с помощью операции Contains и увеличивает ли оно значение.

...