How to compare 2 comma seperated string values and update in existing list at same position?

Viewed 87

I am having a list of string which contains some value and I want to compare values of 2 positions from list and remove matching items from list.

Code :

var list = new List<string>();
 list.Add("Employee1");
 list.Add("Account");
 list.Add("100.5600,A+   ,John");
 list.Add("1.00000,A+     ,John");
 list.Add("USA");

Now i want to compare 2nd and 3rd position :

list.Add("100.5600,A+   ,John");
list.Add("1.00000,A+     ,John");

Compare above 2 records and remove matching records like below:

Expected output :

list.Add("100.5600");
list.Add("1.00000");

This is how i am trying to do :

 var source = list[2].Split(',').Select(p => p.Trim());
 var target = list[3].Split(',').Select(p => p.Trim());
 var result = source.Except(target);

But the problem is I am only getting 100.5600 as output.

Is it possible to compare and update non matching records in existing list?

2 Answers

How about this "beauty"

var list = new List<string>();
list.Add("Employee1");
list.Add("Account");
list.Add("100.5600,A+   ,John");
list.Add("1.00000,A+     ,John");
list.Add("USA");

//prepare the list, I decided to make a tuple with the original string in the list and the splitted array
var preparedItems = list.Select(x => (x, x.Split(',')));

//group the prepared list to get matching items for the 2nd and 3rd part of the split, I therefor used .Skip(1) on the previously prepared array
var groupedItems = preparedItems.GroupBy(x => string.Join(",", x.Item2.Skip(1).Select(y => y.Trim())));

//"evaluate" the group by saying if the items in the group is > 1 only use the first part of the prepared array and if it doesnt have more than one entry use the orignal string 
var evaluatedItems = groupedItems.SelectMany(x => x.Count() > 1 ? x.Select(y => y.Item2[0]) : x.Select(y => y.Item1));

//replace the orignal list with the new result
list = evaluatedItems.ToList();

Edit - preserve original order:

//extended the prepare routine with a third part the index to Keep track of the ordering of the original list
//so the tuple now consits of 3 parts instead of 2 - ([item], [index], [splittedArray])
var preparedItems = list.Select((x, i) => (x, i, x.Split(',')));

//changed to use Item3 intead of Item2 - since the Array now is on third position
var groupedItems = preparedItems.GroupBy(x => string.Join(",", x.Item3.Skip(1).Select(y => y.Trim())));

//instead of returning the simple string here already, return a tuple with the index (y.Item2) and the correct string
var evaluatedItems = groupedItems.SelectMany(x => x.Count() > 1 ? x.Select(y => (y.Item2, y.Item3[0])) : x.Select(y => (y.Item2, y.Item1)));

//now order by the new tuple x.Item1 and only return x.Item2
var orderedItems = evaluatedItems.OrderBy(x => x.Item1).Select(x => x.Item2);

list = orderedItems.ToList();


//one-liner - isn't that a beauty
list = list.Select((x, i) => (x, i, x.Split(','))).GroupBy(x => string.Join(",", x.Item3.Skip(1).Select(y => y.Trim()))).SelectMany(x => x.Count() > 1 ? x.Select(y => (y.Item2, y.Item3[0])) : x.Select(y => (y.Item2, y.Item1))).OrderBy(x => x.Item1).Select(x => x.Item2).ToList();

You may get it easily by checking if items in one is not contained in the other:

   var result = source.Where(x => !target.Contains(x));

To update your old list:

  var source = string.Join(",", source.Where(x => !target.Contains(x)));
Related