1

I believe this is very similar to this, however, I need this based on equal indexes.


I have a list like this:

  Time   | Temp1 | Temp2 |  Type

10:42:00 |  108  |  150  | Unkwon 

10:44:00 |  107  |  160  | Test

10:46:00 |  108  |  130  | Test22 

I have another like this:

ID | Type

40 | New1

80 |  New2

100 | Test22 

I don't have a field to compare both lists. Because of this, I would like to use the index (line number) of the list and <> Type.

So,

Line 1 and 2 should update because they present different type.


Result expected:

  Time   |  Temp1  |  Temp2  |  Type

10:42:00 |   108   |   150   |  New1

10:44:00 |   107   |   160   |  New2

10:46:00 |   108   |   130   |  Test22 

What do I have:

foreach (var x in Graph._listData)
{
     var itemToChange = newData2
         .First(d => 
             d[newData2.IndexOf(1)] == Graph._listData.IndexOf(1)).Type = x.Type;
}

I believe that the whole idea of this code is wrong but it what I got at this point.

The structure of my tables:

public struct GraphData
{
    public double Temp1;
    public double Temp2;
    public DateTime Date;
    public string Type;
}

public struct GraphDataWithID
{
    public int IdHeader;
    public string Type;
}
  • So, how do I accomplish the comparison between two lists based on the index?
Fabio Soares
  • 101
  • 2
  • 12
  • You can just use a `for` loop if this is a `List` or an array. Or you can use `Enumerable.Zip` – juharr Jul 20 '17 at 18:08

3 Answers3

2

No need to use Linq:

var n = Graph._listData.Count;
for (var i = 0; i < n; i++)
    if (Graph._listData[i].Type != newData2[i].Type) {
        var temp = Graph._listData[i]; 
        temp.Type = newData2[i].Type; 
        Graph._listData[i] = temp;
    }

I edited accordingly to what juharr pointed out: if you have a list of immutable structs, you can't modify the struct elements in place.

Antoine C.
  • 3,730
  • 5
  • 32
  • 56
  • Hey, if I try like this I get the error "Cannot modify the return value of 'List.this[int]' because it is not a variable" on the part "Graph._listData[i].Type = newData2[i].Type;" – Fabio Soares Jul 20 '17 at 18:24
  • 1
    @FabioSoares That means you have a list of structs. So you'll have to get a copy of the struct out, change the value, then put the updated copy back into the collection. However if your struct it mutable then you're going to have a lot of other problems. Basically you need to do `var temp = Graph._listData[i]; temp.Type = newData2[i].Type; Graph._listData[i] = temp;` for it to work. – juharr Jul 20 '17 at 18:30
  • Just to note that if instead of list the `_listData` was array, the `struct` members could be modified in place as in the original answer. – Ivan Stoev Jul 20 '17 at 18:49
  • It works!!! Thank you. I marked the other one as correct (because was answered first) but this one also works. Thank you very much. – Fabio Soares Jul 20 '17 at 19:04
  • 1
    Actually this one was answered first, but I would advice you to keep juharr answer as accepted because it is more complete and offers 2 different methods – Antoine C. Jul 20 '17 at 19:06
  • My idea is to save what I found on "Graph._listData[i].Type" to "newData2[i].Type". Right now, if I enter the function with Type="something" in Graph._listData[i] I am leaving Type="" in Graph._listData[i]. This is happening in the part "temp.Type = newData2[i].Type;" because newData2 is empty. In other words,instead of having newData2 with information from "Graph._listData[i].Type" I am leving with both lists with the original value of newData2 – Fabio Soares Jul 20 '17 at 20:08
  • Please create a new question, with precise explanation and properly formatted code – Antoine C. Jul 20 '17 at 20:16
  • @Lovy, sounds like a plan! Thanks. – Fabio Soares Jul 20 '17 at 20:35
2

Note: this works for reference types only.

An alternative to using a for loop is Zip

var zipped = Graph._listData.Zip(
    newData2, 
    (o,n) => new { Original = o, NewDate= n})
foreach(var pair in zipped)
{
    pair.Original.Type = pair.NewData.Type;
}

The nice thing about Zip is that it will stop with the shorter of the two collections, so if newData2 has fewer rows you don't have to do any special checks to make sure the index is out of bounds.

However for a List of structs a for loop would be a better idea since you have to use a temp variable to hold the copy of the struct, update it, and assign it back to the original position in the List.

int end = Math.Min(Graph._listData.Count(), newData2.Count())
for(int i = 0; i < end; i++)
{
    if(Graph._listData[i].Type != newData2[i].Type)
    {
        var temp = Graph._listData[i];
        temp.Type = newData2[i].Type;
        Graph._listData[i] = temp;
    }
}
juharr
  • 31,741
  • 4
  • 58
  • 93
  • If I try to do like this, I get the error "Cannot modify the return value of 'List.this[int]' because it is not a variable" in the part "Graph._listData[i].Type = newData2[i].Type;" – Fabio Soares Jul 20 '17 at 18:39
  • @FabioSoares I'v updated the for loop to handle structs. – juharr Jul 20 '17 at 18:53
  • 1
    @FabioSoares Also I'd highly recommend you change `FormA_DataType` to a `class` if you can because [mutable structs are evil](https://stackoverflow.com/questions/441309/why-are-mutable-structs-evil) – juharr Jul 20 '17 at 18:55
  • It works! I will double check changing FormA_DataType to a class, several people commented about this, thank you! – Fabio Soares Jul 20 '17 at 19:05
  • Hey, it is not working properly... Sorry about that. I should save what I found on "Graph._listData[i].Type" to "newData2[i].Type". Right now, if I enter the function with Type="blabla" in Graph._listData[i] I am leaving Type="" in Graph._listData[i]. This is happening in the part "temp.Type = newData2[i].Type;". I should replace the information from "newData2[i].Type" to "Graph._listData[i].Type" and not the opposite. Can you help me? – Fabio Soares Jul 20 '17 at 19:59
  • And if I try to invert, from "Graph._listData[i] = temp;" to "newData2[i].Type" I get the same error then before - Cannot modify the return value of 'List.this[int]' because it is not a variable – Fabio Soares Jul 20 '17 at 20:01
  • And if I try the "Zip" method, I also get a similar error: Cannot modify the return value of '.Original' because it is not a variable – Fabio Soares Jul 20 '17 at 20:14
1

You can join the lists like this. It uses the overload of the Select method that uses a Func with an index.

var joined = from left in leftList.Select((s, i) => new { s, i })
             join right in rightList.Select((s, i) => new { s, i })
               on left.i equals right.i
             select new { left.s.Time, left.s.Temp1, left.s.Temp2, right.s.Type };
user2023861
  • 8,030
  • 9
  • 57
  • 86