How to compare all items in the lists are equal? - c#

I have a list,in which every item is a list of stings themselves.
How do I check whether all the individual items are same?
static void Main(string[] args)
{
var myList = new List<List<string>>();
var myItem1 = new List<string> { "str1", "str2" };
var myItem2 = new List<string> { "str1", "str2" };
myList.Add(myItem1);
myList.Add(myItem2);
var total = ?? // <- I'm stuck here
Console.WriteLine(total);
Console.ReadKey();
}
Now I want to check if every item inside myList are equal.
I did try this one:Check if two list have the same items, but could not resolve.

You could try something like this which should output true if the list's elements are all the same.
For your code:
if (myList.Any(item => !Enumerable.SequenceEqual(item, myList[0])))

To check if all the lists contain the exact same elements, we can use the SequenceEqual method, which compares both the elements themselves and their order. Since you said that order doesn't matter, however, then we must order the lists first when we do the comparison.
The following line of code returns true if All the lists (except the first one), when reduced to Distinct items and then sorted (OrderBy), are equal to the First list (when reduced to Distinct items and sorted):
bool allAreEqual = myList
.Skip(1)
.All(subList => subList
.Distinct()
.OrderBy(item => item)
.SequenceEqual(myList.First().Distinct().OrderBy(item => item)));
Instead of doing it all in one line, it would be easier to read (in my opinion) and better performing to first get the distinct, ordered lists, and then do the comparison (otherwise we're ordering the first item for each of the other items):
var sortedLists = myList.Select(list => list.Distinct().OrderBy(item => item));
var allAreEqual = sortedLists.Skip(1).All(list => list.SequenceEqual(sortedLists.First()));

Related

C# linq how to get all the first elements of a nested dynamic list?

I have a 2D nested list List<list<dynamic>>, I'd like to get first elements of every second level list and form a new List<dynamic>.
I know .first() gets the first element of a list, but how can I apply it on multiple sub lists?
Thanks in advance.
Proper and efficient way of doing this is as follows:
mainList.Select(subList => subList?.First()).OfType<dynamic>();
This will take care of null lists and null elements
If you want to select all the elements of sublists try following
mainlist.Select(subList => subList).OfType<List<dynamic>>();
This will only take care of null lists
IEnumerable s = listOfLists.Where(lists => lists.Any())
.Select(array => array.First());
Explanation:
First fetch the list of arrays where there are any records by using lists => lists.Any()
Then select the first item from each list and return.
try this please if you want to take the first two elements of each list, and the more elements you want you can increase the integer in the .Take().
List<List<string>> originalList = new List<List<string>>()
{
new List<string>(){"1","1","1"},
new List<string>(){"2","2"},
};
var FirtTwoElementsList = originalList.Select(x => x.Take(2)).ToList();
List<string> FinalList = new List<string>();
foreach (var item in FirtTwoElementsList)
{
FinalList.AddRange(item.ToList<string>());
}

How to Filter a 2-dimensional List?

I'm trying to filter the following list:
List<List<int>> list = new List<List<int>>()
{
new List<int>(){1,2,3,4,5},
new List<int>(){6,7,5,4,5},
new List<int>(){1,3,3,222,1}
}
My filter condition should be: "include only odd numbers", so my list shouldn't have any even numbers after the filter is applied.
My Attempt:
list = list.Where(x => x.Where(y => y%2 == 1).ToList()).ToList()
Desired Output:
List<List<int>> list = new List<List<int>>()
{
new List<int>(){1,3,5},
new List<int>(){7,5,5},
new List<int>(){1,3,3,1}
}
I know how to use Linq on single-dimensional collections, but not sure how to make this one work.
Any ideas?
You may use the following:
list = list.Select(x => x.Where(i => i % 2 == 1).ToList())
.Where(x => x.Any())
.ToList();
Here, we're using Select() to iterate the elements of the outer list, then using Where() to filter the inner list. After that, we call Where() on the outer list to filter out empty inner lists. That last part is optional; feel free to remove it if you need to keep empty lists.
Note: As #Dmitry stated in the comments, it's probably better to use i % 2 != 0 if you want to keep negative odd numbers.

Intersect Two Lists c#

Hello I have these two Lists
List<string> list1 = {"404a49ad-d80f-4ef7-99ab-0996de3b70d4_29190_806.jpg|Name1", "404a49ad-d80f-4ef7-99ab-0996de3b70d4_29197_806.jpg|Name2", "404a49ad-d80f-4ef7-99ab-0996de3b70d4_29210_868.jpg|Name3"}
List<string> list2 = {"404a49ad-d80f-4ef7-99ab-0996de3b70d4_29190_806.jpg","404a49ad-d80f-4ef7-99ab-0996de3b70d4_29197_806.jpg"}
I want to intersect the values of list1 separating by '|' character, with the list2 values, but I want to return the full string of list1 and not only the first part separated by '|' character.
This is the result i want:
var finalList = {"404a49ad-d80f-4ef7-99ab-0996de3b70d4_29190_806.jpg|Name1", "404a49ad-d80f-4ef7-99ab-0996de3b70d4_29197_806.jpg|Name2"}
I dont know if its possible with the instersect function or there is another approach I can use. I've tried using Contains function in a predicate but it takes to much time to find the matches.
I'm using large lists with 2000 elements approx.
Thanks!
Try this, gives the expected results in LinqPad, using your example:
var intersection =
list1.Join(
list2,
l1 => l1.Split('|')[0], //Selector for items from the inner list splits on '|'
l2 => l2, //Select the current item
(l1, l2) => l1);
Compile list2 into a HashSet<string> to allow fast lookups. Then, use a simple Where filter to perform lookups of substrings from list1 against this set.
List<string> list1 = new List<string> { "404a49ad-d80f-4ef7-99ab-0996de3b70d4_29190_806.jpg|Name1", "404a49ad-d80f-4ef7-99ab-0996de3b70d4_29197_806.jpg|Name2", "404a49ad-d80f-4ef7-99ab-0996de3b70d4_29210_868.jpg|Name3" };
List<string> list2 = new List<string> { "404a49ad-d80f-4ef7-99ab-0996de3b70d4_29190_806.jpg", "404a49ad-d80f-4ef7-99ab-0996de3b70d4_29197_806.jpg" };
var list2HashSet = new HashSet<string>(list2);
var finalList = list1.Where(s => list2HashSet.Contains(s.Substring(0, s.IndexOf('|')))).ToList();
Note that s.Substring(0, s.IndexOf('|')) is semantically equivalent to s.Split('|')[0] (assuming that all your strings contain |), but avoids the overhead of allocating another string instance for the text behind the |.
Use where to iterate over the list. Use the Split method to get the first part you are interested in, and then check to see if list2 contains that string. Finally call ToList to convert the result to a list.
var finalList = list1.Where(x => list2.Contains(x.Split(new []{'|'})[0})).ToList();

Check array for duplicates, return only items which appear more than once

I have an text document of emails such as
Google12#gmail.com,
MyUSERNAME#me.com,
ME#you.com,
ratonabat#co.co,
iamcool#asd.com,
ratonabat#co.co,
I need to check said document for duplicates and create a unique array from that (so if "ratonabat#co.co" appears 500 times in the new array he'll only appear once.)
Edit:
For an example:
username1#hotmail.com
username2#hotmail.com
username1#hotmail.com
username1#hotmail.com
username1#hotmail.com
username1#hotmail.com
This is my "data" (either in an array or text document, I can handle that)
I want to be able to see if there's a duplicate in that, and move the duplicate ONCE to another array. So the output would be
username1#hotmail.com
You can simply use Linq's Distinct extension method:
var input = new string[] { ... };
var output = input.Distinct().ToArray();
You may also want to consider refactoring your code to use a HashSet<string> instead of a simple array, as it will gracefully handle duplicates.
To get an array containing only those records which are duplicates, it's a little moe complex, but you can still do it with a little Linq:
var output = input.GroupBy(x => x)
.Where(g => g.Skip(1).Any())
.Select(g => g.Key)
.ToArray();
Explanation:
.GroupBy group identical strings together
.Where filter the groups by the following criteria
.Skip(1).Any() return true if there are 2 or more items in the group. This is equivalent to .Count() > 1, but it's slightly more efficient because it stops counting after it finds a second item.
.Select return a set consisting only of a single string (rather than the group)
.ToArray convert the result set to an array.
Here's another solution using a custom extension method:
public static class MyExtensions
{
public static IEnumerable<T> Duplicates<T>(this IEnumerable<T> input)
{
var a = new HashSet<T>();
var b = new HashSet<T>();
foreach(var x in input)
{
if (!a.Add(x) && b.Add(x))
yield return x;
}
}
}
And then you can call this method like this:
var output = input.Duplicates().ToArray();
I haven't benchmarked this, but it should be more efficient than the previous method.
You can use the built in in .Distinct() method, by default the comparisons are case sensitive, if you want to make it case insenstive use the overload that takes a comparer in and use a case insensitive string comparer.
List<string> emailAddresses = GetListOfEmailAddresses();
string[] uniqueEmailAddresses = emailAddresses.Distinct(StringComparer.OrdinalIgnoreCase).ToArray();
EDIT: Now I see after you made your clarification you only want to list the duplicates.
string[] duplicateAddresses = emailAddresses.GroupBy(address => address,
(key, rows) => new {Key = key, Count = rows.Count()},
StringComparer.OrdinalIgnoreCase)
.Where(row => row.Count > 1)
.Select(row => row.Key)
.ToArray();
To select emails which occur more then once..
var dupEmails=from emails in File.ReadAllText(path).Split(',').GroupBy(x=>x)
where emails.Count()>1
select emails.Key;

Sort one list by another

I have 2 list objects, one is just a list of ints, the other is a list of objects but the objects has an ID property.
What i want to do is sort the list of objects by its ID in the same sort order as the list of ints.
Ive been playing around for a while now trying to get it working, so far no joy,
Here is what i have so far...
//**************************
//*** Randomize the list ***
//**************************
if (Session["SearchResultsOrder"] != null)
{
// save the session as a int list
List<int> IDList = new List<int>((List<int>)Session["SearchResultsOrder"]);
// the saved list session exists, make sure the list is orded by this
foreach(var i in IDList)
{
SearchData.ReturnedSearchedMembers.OrderBy(x => x.ID == i);
}
}
else
{
// before any sorts randomize the results - this mixes it up a bit as before it would order the results by member registration date
List<Member> RandomList = new List<Member>(SearchData.ReturnedSearchedMembers);
SearchData.ReturnedSearchedMembers = GloballyAvailableMethods.RandomizeGenericList<Member>(RandomList, RandomList.Count).ToList();
// save the order of these results so they can be restored back during postback
List<int> SearchResultsOrder = new List<int>();
SearchData.ReturnedSearchedMembers.ForEach(x => SearchResultsOrder.Add(x.ID));
Session["SearchResultsOrder"] = SearchResultsOrder;
}
The whole point of this is so when a user searches for members, initially they display in a random order, then if they click page 2, they remain in that order and the next 20 results display.
I have been reading about the ICompare i can use as a parameter in the Linq.OrderBy clause, but i can’t find any simple examples.
I’m hoping for an elegant, very simple LINQ style solution, well I can always hope.
Any help is most appreciated.
Another LINQ-approach:
var orderedByIDList = from i in ids
join o in objectsWithIDs
on i equals o.ID
select o;
One way of doing it:
List<int> order = ....;
List<Item> items = ....;
Dictionary<int,Item> d = items.ToDictionary(x => x.ID);
List<Item> ordered = order.Select(i => d[i]).ToList();
Not an answer to this exact question, but if you have two arrays, there is an overload of Array.Sort that takes the array to sort, and an array to use as the 'key'
https://msdn.microsoft.com/en-us/library/85y6y2d3.aspx
Array.Sort Method (Array, Array)
Sorts a pair of one-dimensional Array objects (one contains the keys
and the other contains the corresponding items) based on the keys in
the first Array using the IComparable implementation of each key.
Join is the best candidate if you want to match on the exact integer (if no match is found you get an empty sequence). If you want to merely get the sort order of the other list (and provided the number of elements in both lists are equal), you can use Zip.
var result = objects.Zip(ints, (o, i) => new { o, i})
.OrderBy(x => x.i)
.Select(x => x.o);
Pretty readable.
Here is an extension method which encapsulates Simon D.'s response for lists of any type.
public static IEnumerable<TResult> SortBy<TResult, TKey>(this IEnumerable<TResult> sortItems,
IEnumerable<TKey> sortKeys,
Func<TResult, TKey> matchFunc)
{
return sortKeys.Join(sortItems,
k => k,
matchFunc,
(k, i) => i);
}
Usage is something like:
var sorted = toSort.SortBy(sortKeys, i => i.Key);
One possible solution:
myList = myList.OrderBy(x => Ids.IndexOf(x.Id)).ToList();
Note: use this if you working with In-Memory lists, doesn't work for IQueryable type, as IQueryable does not contain a definition for IndexOf
docs = docs.OrderBy(d => docsIds.IndexOf(d.Id)).ToList();

Categories