Intersect Two Lists c# - 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();

Related

LINQ query to find items in a list containing substring elements from a second list

I am trying to list all elements from the first list where it contains a substring equal to all elements from the second list
First list:
C:\Folder\Files_01026666.pdf
C:\Folder\Files_01027777.pdf
C:\Folder\Files_01028888.pdf
C:\Folder\Files_01029999.pdf
Second list:
01027777
01028888
List result should be:
C:\Folder\Files_01027777.pdf
C:\Folder\Files_01028888.pdf
the closer that I got was with .Intersect() but both string-element should be equals
List<string> resultList = firstList.Select(i => i.ToString()).Intersect(secondList).ToList();
List<string> resultList = firstList.Where(x => x.Contains(secondList.Select(i=>i).ToString()));
List<string> resultList = firstList.Where(x => x == secondList.Select(i=>i).ToString());
I know I can do this another way but I'd like to do it with LINQ.
I have looked at other queries but I can find a close comparison to this with Linq. Any ideas or anywhere you can point me to would be a great help.
We can use EndsWith() with Path.GetFileNameWithoutExtension(), as strings in the secondList are not entire file names.
var result = firstList
.Where(path => secondList.Any(fileName => Path.GetFileNameWithoutExtension(path).EndsWith(fileName)));
Try Online
var q = list1.Where(t=>Regex.IsMatch(t,String.Join("|",list2.ToArray()))));
Seems to work for lists of strings. Using Regex can be problem in LINQ. This won't work in Linq2SQL for example.

How to compare all items in the lists are equal?

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()));

How correctly sort a list<string> with numbers?

I met a Difficulty to sort a list item string containing numbers.
I wish I could automatically sort from smallest to largest.
Here is my code:
// Initialize an array to store the numbers
List<string> tab_num = new List<string>();
tab_num.Add("A.3.2.1");
tab_num.Add("A.3.3.1");
tab_num.Add("A.1.0.1");
tab_num.OrderByDescending(num => num).ToList();
Why my result is false ?...
[1] A.3.2.1
[2] A.3.3.1
[3] A.1.0.1
Expected Result:
[1] A.1.0.1
[2] A.3.2.1
[3] A.3.3.1
Thanks a lot
OrderByDescending means from bigger to lower.
Also you are not assigning your result after sorting.
try this:
List<string> tab_num = new List<string>();
tab_num.Add("A.3.2.1");
tab_num.Add("A.3.3.1");
tab_num.Add("A.1.0.1");
tab_num = tab_num.OrderBy(num => num).ToList();
Because you are sorting alphabetically. You should use OrderBy anyway if you want to order "smallest to largest". You need to parse it to somewhat numerical or to version:
Version v = null;
var ordered = tab_num.Select(tab => new { tab, Versionpart = tab.Substring(2) })
.Where(x => Version.TryParse(x.Versionpart, out v))
.OrderBy(x => v)
.Select(x => x.tab)
.ToList();
(assuming that the version is always found at tab.Substring(2))
You should set result of linq query to any variable (and use OrderBy):
List<string> tab_num = new List<string>();
tab_num.Add("A.3.2.1");
tab_num.Add("A.3.3.1");
tab_num.Add("A.1.0.1");
tab_num = tab_num.OrderBy(num => num).ToList();
tab_num.OrderBy(num => num).ToList() is not perform sorting on source list, but returns sorted list.
Actually you don't need linq here, use Sort method:
tab_num.Sort();
But if you want to make your code work, just assign resulting list to a source list:
tab_num = tab_num.OrderBy(x => x).ToList();
the main problem here is that you are not assigning the result to the list as suggested below.
BTW: This list doesn't contains numbers, it contains string so the comparer uses the alphabetic comparator. you should use OrderBy not OrderByDescending. I suggest you to implement your own comparator since your strings are quite simple and the default comparator will give you wrong responses when numbers grows over 9

Finding all integers that exist in list1 that don't exist in list2 with fewest lines of code?

Let's say I have two lists of integers:
List<int> list1 = new List<int> {1,2,3,4,5,6};
List<int> list2 = new List<int> {4,5,6,7,8,9};
What is the quickest way to find all of the integers that exist in list1 but not list2
The simplest solution I can think of is to create a union list from list1 and list2 and remove all of the members from this union that exist in list2
Union = {1,2,3,4,5,6,7,8,9}
Union - list2 = {1,2,3} <- This is my desired result
But maybe there is a simpler and faster one line of code way to get this job done?
list1.Except(list2) (if using .NET 3.5)
If the lists can potentially contain duplicate elements and you want to return any duplicates from list1 then you can do something like this:
var tempSet = new HashSet<int>(list2);
var results = list1.Where(x => !tempSet.Contains(x));
If list2 only contains a few elements then you can probably get away without using a HashSet<T>:
var results = list1.Where(x => !list2.Contains(x));
Though for larger collections you'll find that the HashSet<T> will easily outperform using the list directly: Contains is O(1) for HashSet<T> and O(n) for arbitrary IEnumerable<T> sequences.

FindAll search question

I have a list like this:
item.Add("a");
item.Add("as");
item.Add("b");
item.Add("fgs");
item.Add("adsd");
How can I find all items that start with (for example) "a"?
This "a" is not some hardcoded string, so I will need a function that do this for each string.
I try with FindAll, but I did not figured out how it works.
Br, Wolfy
If by "start with" you mean the first char, then:
item.FindAll(i => i[0] == 'a');
if you mean a string (may be other than 1 char) then:
item.FindAll(i => i.StartsWith("a"));
If you want a different comparison, such as case-insensitive, locale-based, etc. then do the relevant IndexOf such as:
item.FindAll(i => i.IndexOf("a", StringComparison.CurrentCultureIgnoreCase) == 0);
All of the above can be easily adapted to be use a relevant char or string variable or parameter.
If you don't need the extra properties and methods provided by a list, then it will be more efficient to use Where than FindAll as FindAll creates a new list, and does so in all at once, while Where will enumerate the matching results as it is iterated through.
Or with LINQ
from i in items where i.StartsWith("a") select i;
for NET2.0 you may use this method:
'pattern' is an argument to look for (f.e. "a")
private List<string> FindAll(List<string> list, string pattern)
{ // returns found results
return list.FindAll(delegate(string item)
{
return item.StartsWith(pattern);
});
}
I thought you have another list that contains the startswith criteria strings. Lets call your items "words" and the other list "keywords". So the below query will return what you want.
List<string> words = new List<string>();
words.Add("a");
words.Add("as");
words.Add("b");
words.Add("fgs");
words.Add("adsd");
List<string> keywords = new List<string>();
keywords.Add("a");
keywords.Add("b");
var result = words.FindAll(o =>
keywords.Any(a => o.StartsWith(a))
);
This result has the words that starts with any of the keyword from keywords.
List<string> item = new List<string>();
item.Add("a");
item.Add("as");
item.Add("b");
item.Add("fgs");
item.Add("adsd");
var res1 = item.FindAll(i => i.StartsWith("a"));
var res2 = item.Where(i => i.StartsWith("a"));
Try this
item.FindAll(i => i.Contains("a"));
This will return a List containting only the filtered strings.

Categories