开发者

Adding and Couting items in a list

Let's say I have a file that looks like this:

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  

What I want to do is add the 2nd column to a list and have a counter count how many times that item occurs and outputs it with the number and then the counted amount of that number.

Is there a way to do this using a List? If so, how could I go about doing that?

I have tried messing around with things and this is where I was heading.. but it does not work properly

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&开发者_如何学Clt;string>();

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

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

SO for the example above, it would output this:

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

Can someone help me figuring out how to properly do this?


use linq with count and group by (see Count- Grouped section).

create your partList outside the foreach loop and add each item to it inside the loop , so that it would contain all of the elements:

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

(in your example- {128590, 128590, 128588, 128587, 128587, 128590})
and then use LINQ to output the result-

var elementsWithCounts = from p in partList
     group p by p into g
     select new { Item = g.Key, Count = g.Count()};


I would either use a Linq query or a Dictionary

something like

    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 );


Once you have the items split by space, I'm assuming you have a string array looking like so:

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

You can simply perform this operation with a Group By operation.

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.");
}


Basically, you are trying to do this by iterating once, and that is not really going to work, you are going to have to iterate twice, otherwise you will wind up doing an output every time you loop in the foreach, and even if your accurate you are going to be outputting a new line each time. If you need to really use a List instead of a keyed dictionary or hashtable which would be idea for this (key = number, value = count), then you need to build the list first, then summarize the list. You can either use LINQ Group By (which is a bit terse), or create a function that does something similar to what you already have. If you are trying to learn concepts, look at the code below, it could be more condensed but this should be fairly easy to read.

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);
    }

}


Use a hash table instead ofa list. You can save the key as 128590,... and the value the number of times it has occurred. Before you insert the new value check if it is already present in the hashtable by using the Contains operation and if it is increment the value.


I think the biggest problem is getting from raw lines of your text field to individual values. My guess is this is a tab-delimited file with a known constant number of columns, in which case you could use String.Split() to separate the sub-strings. Once you have the strings separated, you can count the instances of the proper column pretty easily with a little LINQ. Given a list or collection of your file's lines:

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜