So basically I have the following 2 IEnumerable lists
List A = {"Personal", "Tech", "Social"}
List B = {"Personal", "Tech", "General"}
Now what I want to achieve is, get the difference between List A and List B, in this case Social and General.
I also need to determine that Social is extra in List A and General is extra in List B to insert and delete accordingly.
I can also have another scenario
List A = {"Personal", "Tech"}
List B = {"Personal", "Tech", "General"}
in this case it would return General"
How can I do that with LINQ?
Here you go
var ListA = new List<string> {"Personal", "Tech", "Social"};
var ListB = new List<string> { "Personal", "Tech", "General" };
var insert = ListA.Except(ListB).ToList();
var delete = ListB.Except(ListA).ToList();
You can use List<T>.Except() Method.
Produces the set difference of two sequences.
public static void Main(string[] args)
{
List<string> A = new List<string> { "Personal", "Tech", "Social" };
List<string> B = new List<string> { "Personal", "Tech", "General" };
var result = A.Except(B);
//Will print "Social"
foreach (var i in result)
{
Console.WriteLine(i);
}
}
Here is a DEMO.
For your second case;
public static void Main(string[] args)
{
List<string> A = new List<string> { "Personal", "Tech" };
List<string> B = new List<string> { "Personal", "Tech", "General"};
var result = B.Except(A);
foreach ( var i in result )
{
Console.WriteLine(i);
}
}
Here is a DEMO.
listA.Except(listB) will give you all of the items in list A that are not in list B.
Than do the reverse.
Use Enumerable.Except
var result = list1.Except(list2).ToList();
var q = A.Intersect(B);//"Personal" , "Tech"
var r = B.Except(A);//"General"
Related
Removing the code as it is private one
List<string> list1 = new List<string> { "0186264-9-2019-019", "0186264-9-2019-020" };
List<string> list2 =new List<string> { "0186264-9-2019-020" };
var d = list1.Except(list2).Any() ;
You can use Except to find the difference between the 2 sets (while optimizing lookups).
bool allElements = !list1.Except(list2).Any();
list1.Except(list2) returns the collection of items in list1 that are in list2. If it does not contain any elements, list2 has all the items of list1 (and maybe other items not in list1).
You can use All method:
var haveAll= list1.All(element=> list2.Contains(element))
You can do using linq expression.
Here code reference.
List<string> list1 = new List<string> { "0186264-9-2019-019", "0186264-9-2019-020" };
List<string> list2 = new List<string> { "0186264-9-2019-020" };
List<string> Common = list1.Where(c => list2.Contains(c)).ToList();
As per your comment you can do using except method.
List<string> list1 = new List<string> { "0186264-9-2019-019", "0186264-9-2019-020" };
List<string> list2 = new List<string> { "0186264-9-2019-020" , "0186264-9-2019-019" };
if (list1.Except(list2).Any())
{
// All list 1 values not present in list 2
}
else
{
// All list 1 values present in list 2
}
Is there a easy way to do this using linq?
I want to check and return true or false, whether any string from list1 contains a string from array1. In the below example that would be string2value and i would want to return true.
Also similarly i want to check whether any array1 would contain a string from list1. That would be string1blah and so that would return true as well. Thanks!
List<string> list1 = new List<string>{"string1","string2value"};
string[] array1 = new string[2] {"string1blah","string2"};
I have a couple of versions, but it does not work all the time.
array1.ToList().Any(a=>list1.Contains(a))
list1.Any(l=>array1.ToList().Contains(l))
You can try this:
var result= list1.Where(s=>array1.Any(s1=>s.Contains(s1)));
Per each string in the list1, you see if there is an element in array1 that is contained in s string.
The way your question is worded it is hard to understand what you want.
If you want all the strings in one list which are substrings of an element in the other list, then this should work:
var substrings = myList.Where(bigstring => myArray.Any(substring => bigstring.Contains(substring)));
If you just want to know whether such an element exists, then do this:
bool myCondition = myList.Any(bigstring => myArray.Any(substring => bigstring.Contains(substring)));
If you're wanting pretty linq, you can do:
static void Main(string[] args)
{
var list1 = new List<string> { "string1", "string2value" };
var array1 = new string[] { "string1blah", "string2" };
var result = from sl in list1
from sa in array1
where sl.Contains(sa) || sa.Contains(sl)
select new { sl, sa };
foreach (var x in result)
{
Console.WriteLine(x);
}
}
Which gives nice output
{ sl = string1, sa = string1blah }
{ sl = string2value, sa = string2 }
You can also use linq query expressions if you want.
Give this code:
List<string> list1 = new List<string> { "string1", "string2value" };
string[] array1 = new string[2] { "string1blah", "string2" };
I want to check and return true or false, whether any string from list1 contains a string from array1. In the below example that would be string2value and i would want to return true.
You can do it like this:
var result = from l1 in list1
from a1 in array1
where l1.Contains(a1)
select l1; // Or select true if you want to just return true
Also similarly i want to check whether any array1 would contain a string from list1. That would be string1blah and so that would return true as well. Thanks!
You can modify the above to achieve it like this:
var result = from l1 in list1
from a1 in array1
where a1.Contains(l1)
select a1;
To return true or false (as you've mentioned in the OP Comments), you would modify the call to count the items contained, and if greater than 0, return true.
EDIT Thanks Dax Fohl
var list1 = new List<string> {"Test1", "Test2", "Test3", "Test4"};
var array1 = new string[] {"Test3", "Test4", "Test5", "Test6"};
var result = list1.Any(s => array1.Any(s.Contains));
I'm having a collection List<dynamic> dList. In that, it has string items and List<string> items. Now I need to organize all the values in a single List.
Just refer the List<dynamic> dList
Case: 1
List<dynamic> dList = new List<dynamic>()
{
"Selva",
new List<string>() {"Bala"},
new List<string>() {"Prayag", "Raj"},
"Pavithran"
};
Case: 2
List<object> bala = new List<dynamic>()
{
"Selva",
new List<object>() {"Bala"},
new List<object>() {"Prayag", "Raj"},
"Pavithran"
};
The Output of the above two List are
My Expected Output is
How could I achieve the expected result from the above List<dynamic>? The List is generated at run time and I cannot to change the structure.
This is a small part of a complex Linq query, so, I need to achieve this in Linq.
If order is important then you can convert every element to a List<string> and then flatten these:
List<dynamic> dList = new List<dynamic>()
{
"Selva",
new List<string>() {"Bala"},
new List<string>() {"Prayag", "Raj"},
"Pavithran"
};
var flattenedList = dList.SelectMany(d =>
{
if (d is string)
{
return new List<string>() { d };
}
else if (d is List<string>)
{
return (d as List<string>);
}
else
{
throw new Exception("Type not recognised");
}
});
Or, as a sexy one-liner with no type-checking (so...use at your own risk!)
dList.SelectMany(d => d as List<string> ?? new List<string>() { d })
Or, finally, in LINQ syntax:
var newList =
(from d in dList
from d2 in EnsureListOfString((object)d)
select d2
);
public List<string> EnsureListOfString(object arg)
{
List<string> rtn = arg as List<string>;
if (rtn == null)
{
if (arg is string)
{
rtn = new List<string>() { arg as string };
}
else
{
throw new Exception("Type not recognised.");
}
}
return rtn;
}
If the order of the elements is not important, you can do this:
dList.OfType<string>().Concat(dList.OfType<List<string>>().SelectMany(l => l));
This first selects all string elements from the list, then selects all List<string> elements and flattens them using SelectMany and finally concats all strings.
I have been trying to figure out how to randomly order two lists the same eg.
List<string> list = new List<string>();
list.Add("RedHat");
list.Add("BlueHat");
list.Add("YellowHat");
List<image> list2 = new List<image>();
list.Add(Properties.Resources.RedHat);
list.Add(Properties.Resources.BlueHat);
list.Add(Properties.Resources.YellowHat);
now if i wanted to order these so that redhat and the redhat image stay aligned how may i do this?And is there a way to combine these lists and then shuffle using a dictionary or keyvalue pair or something along those lines?
Wrap the two in an object:
class WrapperObject {
public string Name { get; set; }
public object Resource { get; set; }
}
Add them to a list:
var list = new List<WrapperObject>();
list.Add(new WrapperObject() {
Name = "RedHat",
Resource = Properties.Resources.RedHat
});
..randomize:
var rnd = new Random();
list = list.OrderBy(x => rnd.Next(50)).ToList();
Any specific reason why you want them in two lists, you could just create a list of keyvaluepairs like this:
var list = new List<KeyValuePair<string, image>> ();
list.Add(new KeyValuePair<string, image>("RedHat", (Properties.Resources.RedHat)));
list.Add(new KeyValuePair<string, image>("BlueHat", (Properties.Resources.BlueHat)));
list.Add(new KeyValuePair<string, image>("YellowHat", (Properties.Resources.YellowHat)));
You could store the data in a Tuple<,> but if you had more than 2 elements its worth just creating an explicit class to store the data.
Tuple example:
List<Tuple<string, image>> list = new List<Tuple<string, image>>();
list.Add(new Tuple<string,image>("RedHat", Properties.Resources.RedHat));
// etc...
LINQ-fu version:
var rng = new Random();
var res = Enumerable.Zip(list, list2, (e1, e2) => new { e1, e2 })
.OrderBy(x => rng.Next())
.Aggregate(new { list1 = new List<string>(), list2 = new List<image>() },
(lists, next) =>
{
lists.list1.Add(next.e1);
lists.list2.Add(next.e2);
return lists;
});
list = res.list1;
list2 = res.list2;
The following code should do what you want:
var list1 = new List<string>
{
"RedHat",
"BlueHat",
"YellowHat"
};
var list2 = new List<int>
{
1,
2,
3
};
var combined = list1.Zip(list2, (a, b) => new { a, b }).Shuffle(new Random()).ToList();
list1 = combined.Select(i => i.a).ToList();
list2 = combined.Select(i => i.b).ToList();
You'll need the following extension method:
public static class ShuffleExtension
{
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, Random rng)
{
T[] elements = source.ToArray();
for (int i = elements.Length - 1; i >= 0; i--)
{
int swapIndex = rng.Next(i + 1);
yield return elements[swapIndex];
elements[swapIndex] = elements[i];
}
}
}
First put the corresponding elements together, then apply random order:
var rnd = new Random();
var ordered = list.Zip(list2, Tuple.Create).OrderBy(el => rnd.Next()).ToArray();
You can easily extract back the individual lists, if needed:
var ordered_list = ordered.Select(tuple => tuple.Item1).ToList();
var ordered_list2 = ordered.Select(tuple => tuple.Item2).ToList();
in linq, is it possible to combine many lists (of the same type), such that two lists,
list 1 = {a,b,c} and list 2 = {x,y,z}
turns into {[1,a] , [1,b] , [1,c] , [2,x] , [2,y] , [2,z] }
where [] represents a pair containing a "list identifier"
The problem is from having decks of arbitrary cards, where each deck is a list in a collection of lists.
I'm trying to create a query such that I can select only cards in a certain deck, or cards similar to 2 or more decks.
This is probably a duplicate question, but I don't know how to search for the question further then I already have.
List<List<int>> lists;
var combined = lists.Select((l, idx) => new { List = l, Idx = idx })
.SelectMany(p => p.List.Select(i => Tuple.Create(p.Idx + 1, i)));
var list1 = new List<string>() {a,b,c};
var list2 = new List<string>() {x,y,z};
var combined = list1.Select(x => new { id = 1, v = x }).Concat(list2.Select(x => new { id = 2, v = x }));
Normally I'd suggest Enumerable.Zip for combining multiple lists, however you seem to actually want to concatenate multiple lists with a list counter.
public IEnumerable<Tuple<int,T>> Combine<T>(params IEnumerable<T>[] lists) {
return lists.Select((x,i) => x.Select(y => Tuple.Create(i+1,y))).SelectMany (l =>l);
}
UPDATE
Completely missed that SelectMany has the index option so the above code can be written as
public IEnumerable<Tuple<int,T>> Combine<T>(params IEnumerable<T>[] lists) {
return lists.SelectMany((x,i) => x.Select(y => Tuple.Create(i+1,y)));
}
Then you can do
var list1 = new List<string> { "a", "b", "c" };
var list2 = new List<string> { "x", "y", "z" };
var combined = Combine(list1,list2);
Combined will be enumerable of tuples, with Item1 being the list index identifier (starting at 1) and Item2 being the value.
This method will handle multiple lists so you could just as easily call it with:
var list3 = new List<string> { "f", "g" };
var combined = Combine(list1,list2,list3);
You can merge the lists like:
var first = new List<string> {"a","b","c"};
var second = new List<string> {"x","y","z"};
var merged = first.Select(item => new { ListIndex = 1, Value = item}).ToList();
merged.AddRange(second.Select(item => new { ListIndex = 2, Value = item});
//or use concat
var merged = first.Select(item => new { ListIndex = 1, Value = item});
.Concat(second.Select(item => new { ListIndex = 2, Value = item});
Alternatively if you have the sources in something like:
List<List<string>> lists = new List<List<string>>
{
new List<string> {"a","b","c"},
new List<string> {"x","y","z"}
};
you can do:
var merged = lists.SelectMany((item, index) =>
item.Select(s => new { ListIndex = index, Value = s}));
Note that this will produce a 0-based list, so if you really need a 1-base list, just do ListIndex = index +1.
Also, if you will use this a lot, I would create it as an specific entity, something like
struct ListIdentValue
{
public int ListIndex {get; private set;}
public string Value {get; private set;}
public ListIdentValue(int listIndex, string value) {...}
}
Try using Concat
new[] {'a','b','c'}
.Select(v=>new Tuple<int,char>(1, v))
.Concat(
new[] {'x','y','z'}.Select(v=>new Tuple<int,char>(2, v))
)
string[] a = { "a", "b", "c" };
string[] b = { "x", "z", "y" };
var t =
(
from ai in a
select new { listNo = 1, Item = ai }
).Union
(
from bi in b
select new { listNo = 2, Item = bi }
);
or
var t =
(
from ai in a
select new object[] { 1, ai }
).Union
(
from bi in b
select new object[] { 2, bi }
);