What is the best way to compare two lists based on values, order and the number of values. So all of the lists below should be different.
var list1 = new List<string> { "1", "2" };
var list2 = new List<string> { "2", "1" };
var list3 = new List<string> { "1", "2", "3" };
How about using SequenceEqual.
See http://ideone.com/yZeYRh
var a = new [] { "1", "2", "3" };
var b = new [] { "1", "2" };
var c = new [] { "2", "1" };
Console.WriteLine(a.SequenceEqual(b)); // false
Console.WriteLine(a.SequenceEqual(c)); // false
Console.WriteLine(c.SequenceEqual(b)); // false
It comes from the namespace System.Linq and can be used on any IEnumerable.
You can also pass it an IEqualityComparer to for example also do:
var d = new [] { "a", "B" };
var e = new [] { "A", "b" };
Console.WriteLine(d.SequenceEqual(e, StringComparer.OrdinalIgnoreCase)); // true
I like Zip for this, but you still need to manually compare Count.
lista.Count() ==listb.Count() && lista.Zip(listb, Equals).All(a=>a);
Related
If I have the following sublists, how can I remove 'duplicates' so that I only have L1, L2 and L3 remaining? I don't mind which variant remains, as long as the duplicates are gone.
List<List<string>> mylist = new List<List<string>>();
List<string> L1 = new List<string> { "a", "b", "c" };
List<string> L2 = new List<string> { "d", "e", "f" };
List<string> L3 = new List<string> { "g", "h", "i" };
List<string> L4 = new List<string> { "c", "a", "b" };
List<string> L5 = new List<string> { "a", "c", "b" };
List<string> L6 = new List<string> { "f", "d", "e" };
It's worth mentioning that I'm removing the duplicates to improve performance in another part of my program, so anything too intensive would not be appropriate. Thanks!
you can use Linq by applying Distinct function with a custom comparer like the following code:
1 - Create Custom generic comparer for List<T>:
public class GenericComparer<T> : IEqualityComparer<List<T>>
{
public bool Equals(List<T> x, List<T> y)
{
return x.Count == y.Count && x.All(xx => y.Contains(xx));
}
public int GetHashCode(List<T> obj)
{
int hashCode = 0;
foreach(T str in obj)
{
hashCode ^= str.GetHashCode();
}
return hashCode;
}
}
2 - call Distinct function with StringListComparer like :
List<List<string>> mylist = new List<List<string>>()
{
new List<string> { "a", "b", "c" },
new List<string> { "d", "e", "f" },
new List<string> { "g", "h", "i" },
new List<string> { "c", "a", "b" },
new List<string> { "a", "c", "b" },
new List<string> { "f", "d", "e" },
};
var result = mylist.Distinct(new GenericComparer<string>()).ToList();
3 - Demo
foreach(List<string> strList in result)
{
Console.WriteLine(string.Join(",", strList));
}
4- Result
a,b,c
d,e,f
g,h,i
If you have a list of integer, you can call Distinct method like :
var result1 = mylist1.Distinct(new GenericComparer<int>()).ToList();
I hope this help you out.
I can get values which are already matched. But i can't get unmatched values. How to make it work. Give me some advice guys
private void button13_Click(object sender, EventArgs e)
{
String a = textBox3.Text;
String b = textBox4.Text;
string test = "";
string[] titles1 = a.Split(new[] { ';', '\t', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
string[] titles2 = b.Split(new[] { ';', '\t', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
var duplicates = titles1.Distinct().Concat(titles2.Distinct()).GroupBy(title => title).Where(possibleDuplicates => possibleDuplicates.Skip(1).Any()).Select(duplicate => duplicate.First());
int i = 0;
foreach (string duplicate in duplicates)
{
//test = test + duplicate + "\r\n";
System.Data.DataTable table = new System.Data.DataTable();
table.Columns.Add("Missed call");
table.Rows.Add(duplicate);
Excel_read.DataSource = table;
}
}
This may help for you
var result = titles1.Except(titles2).Concat(titles2.Except(titles1)).ToArray();
To find the differences you may use the following code (it is written on the fly, I don't say it is an performance-optimized algorithm, it is just an idea how your problem may be solved):
var list1 = new List<int> {1, 2, 3, 5};
var list2 = new List<int> {1, 2, 4, 5, 6};
var differences = list1.Where(v => !list2.Contains(v)).Concat(
list2.Where(v => !list1.Contains(v)));
// Or this compact version:
// var differences = list1.Except(list2).Concat(list2.Except(list1));
The differences IEnumerable will will contain the following result:
{3, 4, 6}
This way:
List<string> list1 = new List<string> { "1", "2", "3", "4", "5", "7", "9"};
List<string> list2 = new List<string> { "1", "2", "3", "4", "5", "6", "8" };
List<string> list3 = list1;
list3.AddRange(list2);
list3 = list3.GroupBy(x => x).Where(x => x.Count() == 1).Select(x => x.Key).ToList();
I have data table having rows like
ID Name
2 A
4 B
3 C
5 D
1 E
List order = new List() { "1", "3", "2", "5", "4" }
--------------order by list-----------------
ID Name
1 E
3 C
2 A
5 D
4 B
can anyone help to implement this.. I am using DataTable in Winforms.
Another solution to the already given ones, would be to loop your order list and then sort your source list.
// source list
List<Foo> lSource = new List<Foo>() {
new Foo() { ID = 2, Name = "A" },
new Foo() { ID = 4, Name = "B" },
new Foo() { ID = 3, Name = "C" },
new Foo() { ID = 5, Name = "D" },
new Foo() { ID = 1, Name = "E" },
};
// order list
List<int> order = new List<int>() { 1, 3, 2, 5, 4 };
// loop order list and sort source list
order.ForEach(x =>
{
lSource = lSource.OrderBy(g => g.ID == x).ToList();
});
// set datasource
dataGridView1.DataSource = lSource;
I just added a class Foo containing an int ID and a string Name, because you didn't share your whole code.
I think you can join your order and your datatable with AsEnumerable method and on on part you can equalize both of them and select rows, then you can generate a DataTable from that query with CopyToDataTable method.
var dt = new DataTable();
var dc = new DataColumn() { ColumnName = "ID", DataType = typeof(string) };
dt.Columns.Add(dc);
dc = new DataColumn() { ColumnName = "Name", DataType = typeof(string) };
dt.Columns.Add(dc);
dt.Rows.Add(new object[] { "2", "A" });
dt.Rows.Add(new object[] { "4", "B" });
dt.Rows.Add(new object[] { "3", "C" });
dt.Rows.Add(new object[] { "5", "D" });
dt.Rows.Add(new object[] { "1", "E" });
List<string> order = new List<string>() { "1", "3", "2", "5", "4" };
var query = from item in order
join row in dt.AsEnumerable() on item equals row.Field<string>("ID")
select row;
var result = query.CopyToDataTable();
result will be;
I'm not sure this is the best way or not but this seems to fit with your case.
You can join both lists (the one with items and the one with sorted id's) and then select the items:
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var list = new List<Item>{
new Item { Id = 2, Text = "A" },
new Item { Id = 4, Text = "B" },
new Item { Id = 3, Text = "C" },
new Item { Id = 5, Text = "D" },
new Item { Id = 1, Text = "E" }
};
var sortorder = new List<int> { 1, 3, 2, 5, 4 };
var sortedlist = sortorder.Join(list, x => x, y => y.Id, (x,y) => y);
foreach(var item in sortedlist)
Console.WriteLine("{0} {1}", item.Id, item.Text);
}
}
Was wondering is it possible to reverse a dictionary in a single LINQ statement?
The structure is as follows;
Dictionary<string, List<string>> original = new Dictionary<string, List<string>>()
{
{"s", new List<string>() { "1", "2", "3" }},
{"m", new List<string>() { "4", "5", "6" }},
{"l", new List<string>() { "7", "8", "9" }},
{"xl", new List<string>() { "10", "11", "12" }},
};
which i would like to convert to a dictionary of type;
Dictionary<string, string> Reverse = new Dictionary<string, string>()
{
{"1", "s"},
{"2", "s"}, //and so on
};
If you do:
var reversed = original.SelectMany(x => x.Value.Select(y => new KeyValuePair<string, string>(y, x.Key)));
then you get:
1 - s
2 - s
3 - s
4 - m
5 - m
etc.
Something like:
var result = (from kvp in original
from value in kvp.Value
select new {Key = value, Value = kvp.Key}).ToDictionary(a => a.Key, a => a.Value);
Or, if you prefer the method syntax:
var result = original.SelectMany(kvp => kvp.Value.Select(v => new {Key = v, Value = kvp.Key}))
.ToDictionary(a => a.Key, a => a.Value);
you can use a SelectMany to split the value sublists, and then reverse the Keys & Values into a new Dictionary using ToDictionary
var result = original
.SelectMany(k=> k.Value.Select(v => new { Key = v, Value = k.Key } ))
.ToDictionary( t=> t.Key, t=> t.Value);
For that you can use the SelectMany LINQ extension method:
var original = new Dictionary<string, List<string>>
{
{ "s", new List<string> { "1", "2", "3" } },
{ "m", new List<string> { "4", "5", "6" } },
{ "l", new List<string> { "7", "8", "9" } },
{ "xl", new List<string> { "10", "11", "12" } },
};
var keyValuePairs = original.SelectMany(o => o.Value.Select(v => new KeyValuePair<string, string>(v, o.Key)));
I have the following string arrays:
var array1 = new String[] { "A", "B", "C", "D" }
var array2 = new String[] { "B", "D" }
I need to do the following:
1) Find the item in array2 which appears firts in array1 (In this case is B);
2) Get the item in (1) and all the others which appear after it in array1.
So in this case I would get:
var array3 = new String[] { "B", "C", "D" }
I was trying to do it, in one step, using a lambda expression.
Is this possible?
var array3 = array1.SkipWhile(x => !array2.Contains(x)).ToArray();