0

I have a ListView with 2 columns. For example's sake, we'll say it looks like this:

ColA    | ColB  
-----------------
001     |  
002     |  
003     |  
004     |  
005     |  

I have a text file that contains the following lines:

001  
002  
004  
005  
008  

I'm trying to read through the file line by line, and if the number matches a number in ColumnA, I want to add it to ColumnB. That works fine (see my example below). However, I'd also like to add any non-matches as a new ListViewItem. I can't figure that part out. Here's what I have so far:

foreach (string textfileitem in TheTextFile)
{
    foreach (ListViewItem item in ListView1.Items)
    {
        var existingitem = item.SubItems[0];

        if (existingitem.Text == textfileitem)
        {
            item.SubItems[1].Text = textfileitem;
        }
    }
}

I'm not sure how to handle any non-matches and add them to the ListView. the end result would look like this:

ColumnA | ColumnB
----------------- 
001     | 001
002     | 002
003     | 
004     | 004
005     | 005
-       | 008

As always, your help is appreciated!

Jeff Brady
  • 1,454
  • 7
  • 35
  • 56
  • I know that you are not using this method but this [**`link`**](http://stackoverflow.com/a/12974655/1577396) may help you. – Mr_Green Nov 12 '12 at 17:24

4 Answers4

1

Run through your columnA, create a dictionary of <String,YourDataSourceItem>. Run through your file - test match using TryGetValue. If found, set columnB. If not, create a new item.

Victor Zakharov
  • 25,801
  • 18
  • 85
  • 151
  • Unfortunately I'm not familiar with using a dictionary, but I will check it out. Thank you! – Jeff Brady Nov 12 '12 at 17:01
  • Would "ContainsKey" work here? Load ColumnA into a dictionary, then loop thru the text file with something like `if (dictionary.ContainsKey(textfileitem)) { //do something ? } else { //do something else }` – Jeff Brady Nov 12 '12 at 17:08
  • 1
    @Vertekal: `ContainsKey` would work too, but it requires two lookups, if the item is present, because first you would test if present, and then retrieve the item. `TryGetValue` saves you an extra lookup. Not a big difference in performance, because dictionary is fast anyway, just my style of working with it. – Victor Zakharov Nov 12 '12 at 17:34
  • Thank you! I think this will work. I have a foreach loop that adds the ColumnA items to a dictionary. Then, I have a foreach loop that goes thru the text file and does a TryGetValue. The only part I'm not sure about is if the TryGetValue is true, how to add the text file item to ColumnB in the same row as the matching ColumnA item. I need to learn more about ListViewItems I guess .. :) – Jeff Brady Nov 12 '12 at 18:06
  • 1
    @Vertekal: depends on your underlying `DataSource`. If it's a `DataTable`, your `TryGetValue` will retrieve a `DataRow` (into the 2nd parameter, ByRef). Then you would simply say `DataRow("ColumnB") = newColumnBValue` (read previously from a file). You should not be assigning anything by using `ListViewItem` and rather work through business logic. – Victor Zakharov Nov 12 '12 at 18:30
0

Here is another way to do it:

List<string> missingItems = new List<string>();
foreach (string textfileitem in TheTextFile)
{
    foreach (ListViewItem item in ListView1.Items)
    {
        var existingitem = item.SubItems[0];

        if (existingitem.Text == textfileitem)
        {
            item.SubItems[1].Text = textfileitem;
        }
        else
        {
            missingItems.Add(textfileitem);
        }
    }
}
foreach (string missingItem in missingItems)
{
    // Add missing item to your ListView.
    ListView1.Items.Add("missing").SubItems.Add(missingItem);
}
Polyfun
  • 9,479
  • 4
  • 31
  • 39
  • I tried something similar, but it incorrectly adds items to the missingItems list. During the 2nd foreach loop, the existing item may not match the textfileitem until it has looped several times. The items being added to missingItems may actually match during the next pass of the initial foreach loop. I hope that made sense ... – Jeff Brady Nov 12 '12 at 16:56
0

I would do something like this:

List<string> listItems = ListView1.Items.Select(item => item[0].ToString())  // Get list of current items
foreach (string textItem in TheTextFile.Except(listItems)) { // Get all text items that are not in the current list
// Add missing list view item
}
Mike Cofoed
  • 151
  • 1
  • 4
0

Based on @Neolisk 's suggestion, I rethought my process and ended up using a DataGridView bound to a DataTable. ColumnA gets populated by data in the DataTable. Then, I put each item in ColumnA into a Dictionary.

My code now looks like this:

int count;
Dictionary<string, int> d = new Dictionary<string, int>();

foreach (DataRow dr in dataSet1.Tables["Table1"].Rows)
{
    d.Add((string)dr[0], count);
    count++;
}

foreach (string textfileitem in TheTextFile)
{
    string item = //specific data from textfileitem
    int value;

    if (d.TryGetValue(item, out value)
    {
        DataRow[] dr = dataSet1.Tables["Table1"].Select("ColumnA = " + item");
        dr[0]["ColumnB"] = item;
    }
    else
    {
        dataTable1.Rows.Add(null, item);
    }
}

At least I hope that's accurate. I tried to make my code generic and get rid of the non-essential stuff.

Jeff Brady
  • 1,454
  • 7
  • 35
  • 56