How do you concatenate Lists in C#? - c#

If I have:
List<string> myList1;
List<string> myList2;
myList1 = getMeAList();
// Checked myList1, it contains 4 strings
myList2 = getMeAnotherList();
// Checked myList2, it contains 6 strings
myList1.Concat(myList2);
// Checked mylist1, it contains 4 strings... why?
I ran code similar to this in Visual Studio 2008 and set break points after each execution. After myList1 = getMeAList();, myList1 contains four strings, and I pressed the plus button to make sure they weren't all nulls.
After myList2 = getMeAnotherList();, myList2 contains six strings, and I checked to make sure they weren't null... After myList1.Concat(myList2); myList1 contained only four strings. Why is that?

Concat returns a new sequence without modifying the original list. Try myList1.AddRange(myList2).

Try this:
myList1 = myList1.Concat(myList2).ToList();
Concat returns an IEnumerable<T> that is the two lists put together, it doesn't modify either existing list. Also, since it returns an IEnumerable, if you want to assign it to a variable that is List<T>, you'll have to call ToList() on the IEnumerable<T> that is returned.

targetList = list1.Concat(list2).ToList();
It's working fine I think so. As previously said, Concat returns a new sequence and while converting the result to List, it does the job perfectly.

It also worth noting that Concat works in constant time and in constant memory.
For example, the following code
long boundary = 60000000;
for (long i = 0; i < boundary; i++)
{
list1.Add(i);
list2.Add(i);
}
var listConcat = list1.Concat(list2);
var list = listConcat.ToList();
list1.AddRange(list2);
gives the following timing/memory metrics:
After lists filled mem used: 1048730 KB
concat two enumerables: 00:00:00.0023309 mem used: 1048730 KB
convert concat to list: 00:00:03.7430633 mem used: 2097307 KB
list1.AddRange(list2) : 00:00:00.8439870 mem used: 2621595 KB

I know this is old but I came upon this post quickly thinking Concat would be my answer. Union worked great for me. Note, it returns only unique values but knowing that I was getting unique values anyway this solution worked for me.
namespace TestProject
{
public partial class Form1 :Form
{
public Form1()
{
InitializeComponent();
List<string> FirstList = new List<string>();
FirstList.Add("1234");
FirstList.Add("4567");
// In my code, I know I would not have this here but I put it in as a demonstration that it will not be in the secondList twice
FirstList.Add("Three");
List<string> secondList = GetList(FirstList);
foreach (string item in secondList)
Console.WriteLine(item);
}
private List<String> GetList(List<string> SortBy)
{
List<string> list = new List<string>();
list.Add("One");
list.Add("Two");
list.Add("Three");
list = list.Union(SortBy).ToList();
return list;
}
}
}
The output is:
One
Two
Three
1234
4567

Take a look at my implementation. It's safe from null lists.
IList<string> all= new List<string>();
if (letterForm.SecretaryPhone!=null)// first list may be null
all=all.Concat(letterForm.SecretaryPhone).ToList();
if (letterForm.EmployeePhone != null)// second list may be null
all= all.Concat(letterForm.EmployeePhone).ToList();
if (letterForm.DepartmentManagerName != null) // this is not list (its just string variable) so wrap it inside list then concat it
all = all.Concat(new []{letterForm.DepartmentManagerPhone}).ToList();

Related

How do I compare two lists where one list starts with the other, and only return the "overhang" elements?

I have two List<string>:
List 1:
snap
crackle
List 2:
snap
crackle
pop
bang
List 2 will always start with the same elements as List 1, but will always have some extra elements "hanging off the end." I want to return a list of just these "overhang elements."
So in the above example, I want a list of:
pop
bang
Is there a LINQ operator that does this?
You can use Except extension method:
var list1 = new List<string> { "snap", "crackle" };
var list2 = new List<string> { "snap", "crackle", "pop", "bang" };
var result = list2.Except(list1).ToList();
Ivan Stoev pointed that the solution above will produce the set difference. If you want the list difference and the second list always contains elements from the first list at the beginning you can use this solution:
var result = list2.Skip(list1.Count).ToList();
Run this example on .NET Fiddle.
You can use the Except() linq method to do this:
var onlyIn2 = list2.Except(list1);

Most efficient way to compare two lists and delete the same

I want to compare two lists and get the valid words into a new list.
var words = new List<string>();
var badWords = new List<string>();
//this is just an example list. actual list does contain 700 records
words.Add("Apple");
words.Add("Moron");
words.Add("Seafood");
words.Add("Cars");
words.Add("Chicken");
words.Add("Twat");
words.Add("Watch");
words.Add("Android");
words.Add("c-sharp");
words.Add("Fool");
badWords.Add("Idiot");
badWords.Add("Retarded");
badWords.Add("Twat");
badWords.Add("Fool");
badWords.Add("Moron");
I am looking for most efficient way to compare the lists and put all the 'good' words into a new list. The finalList shouldn't contain "Moron", "Twat" and "Fool".
var finalList = new List<string>();
Or is it unnecessary to create a new List? I am happy to hear your ideas!
Thank you in advance
Use EnumerableExcept function storing in System.Linq namespace
finalList = words.Except(badWords).ToList();
Most efficient way to save your time and also the fastest way to do it, because Except implementation uses Set, which is fast
Use Enumerable.Except:
List<string> cleanList = words.Except(badWords).ToList();
This is efficient because Except uses a set based approach.
An even more efficient approach is to avoid that "bad" words are added to the first list at all. For example by using a HashSet<string> with a case-insensitive comparer:
var badWords = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase){ "Idiot", "Retarded", "Twat", "Fool", "Moron" };
string word = "idiot";
if (!badWords.Contains(word))
words.Add(word);
https://msdn.microsoft.com/library/bb908822(v=vs.90).aspx
var words = new List<string>();
var badWords = new List<string>();
//this is just an example list. actual list does contain 700 records
words.Add("Apple");
words.Add("Moron");
words.Add("Seafood");
words.Add("Cars");
words.Add("Chicken");
words.Add("Twat");
words.Add("Watch");
words.Add("Android");
words.Add("c-sharp");
words.Add("Fool");
badWords.Add("Idiot");
badWords.Add("Retarded");
badWords.Add("Twat");
badWords.Add("Fool");
badWords.Add("Moron");
var result = words.Except(badWords).ToList();
Edit: Got in late.
you can use contains method
words.Where(g=>!badWords.Contains(g)).ToList()
If your don't want to create a new List you can remove the bad words from your existing List with RemoveAll()
words.RemoveAll(badWords.Contains);

In C#, What is the best way to see if a list contains another list?

If i have a list of strings, what is the best way to determine if every element in another list is contains in this list. For example:
List<string> list = new List<string>();
list.Add("Dog");
list.Add("Cat");
list.Add("Bird");
List<string> list2 = new List<string>();
list.Add("Dog");
list.Add("Cat");
if (list.ContainsList(list2))
{
Console.Write("All items in list2 are in list1")
}
I am trying to determine if there something like this "ContainsList" method?
if (!list2.Except(list).Any())
Loved SLaks version. Just for completeness, you can use HashSet method IsSubsetOf when performing set operations (also check IsSupersetOf method). There are pros and cons for this approach. Next code shows an example:
var list1 = new HashSet<string>{ "Dog", "Cat", "Bird" };
var list2 = new HashSet<string>{ "Dog", "Cat" };
if (list2.IsSubsetOf(list1))
{
Console.Write("All items in list2 are in list1");
}
Except method is streaming in nature. In query list2.Except(list1) list1 is buffered completely into memory, and you iterate one item at a time through list2. IsSubsetOf works eagerly in the opposite manner. This starts to make a difference when you have huge sets of data.
To analyse the worst case performance, here is some code from Except implementation at Monos Enumerable (dotPeek gives very similar results, just less readable)
var items = new HashSet<TSource> (second, comparer); //list1.Count
foreach (var element in first) //list2.Count
if (items.Add (element)) //constant time
yield return element;
as result O(list1.Count + list2.Count), loops aren't nested.
IsSubset has next method call, if second IEnumerable is HashSet (decompiled via dotPeek):
private bool IsSubsetOfHashSetWithSameEC(HashSet<T> other)
{
foreach (T obj in this) //list2.Count
if (!other.Contains(obj)) //constant time
return false;
return true;
}
Resulting in O(list2.Count) if list1 is a HashSet.
How about,
var list1 = new List<string>{"Dog","Cat","Bird"};
var list2 = new List<string>{"Dog","Cat"};
if (list1.Union(list2).SequenceEqual(list1))
Console.Write("All items in list2 are in list1");
How about this
list1.intersect (list2).ToList ().Foreach ((x)=>
{
Console.Writeline (x)
});

Problems with Lists and Dictionaries

I'm having a problem with a Dictionary of Lists for both the Key and Value.
My dictionary is set up as this
Dictionary<List<string>,List<double>> f = new Dictionary<List<string>,List<double>>();
(it's like this for a very specific reason).
My problem is how to get the two lists out into their own lists. I have tried the following
List<string> s = new List<string>(f.Keys);
List<string> s = f.Select(kvp=>kvp.Keys).ToList()
List<string> s = f.Select(kvp=>kvp.Keys);
List<string> s = f.Keys;
as well as a variant using IEnumerable. No matter what I do, I can't seem to retrieve the Keys (or using f.Values, the values).
Any help here would be appreciated.
A list of strings seems like a VERY odd key for a dictionary, and will have complexities of its own, but you seem confident that it's correct, so I'll focus on your actual question.
Since Keys is a collection of key values, each of which is a List<string>, any of these should work:
List<List<string>> s = f.Select(kvp=>kvp.Key).ToList();
List<List<string>> s = f.Keys.ToList();
If you want ALL strings as a single list (essentially joining all of the lists together), you can use:
List<string> s2 = f.SelectMany(kvp => kvp.Key).ToList();
The SelectMany essentially selects each item from the collection within each key across the whole dictionary.
Lol This is probably the funniest thing I've seen in a while.
Alright. In c# there is a structure called KeyValuePair<TKey, TValue>. You can then iterate through the entire dataset with foreach and get access to what you want.
foreach(KeyValuePair<<List<string>,List<double>> item in f) {
List<string> key = item.key;
List<double> value = item.value;
}
If you have only 1 key,meaning 1 list of strings:
List<string> newf = f.Keys.ElementAt(0);
If you have more place another index.
Or check if the list as some item so that would be the list to retrieve:
List<string> newf = f.Keys.Single(k => k.Contains("SomeString"));
//this must exist or it will throw exception.
Get a key by checking if the corresponding values sum is above(or less,or equal...)
var newf1 = f.Where(k => k.Value.Sum() > 10).Select(v => v.Key);

How to logical and (^ , logical conjunction) string lists - C#

Alright. Now this question may come to you weird but i have to solve it. Now the issue is simple. Let me explain with good example
Lets say that i have the following string lists. Each line is a list and those lists will be logical anded
my,car,fly,surf,buy
house,home,car,fly,buy
fly,king,rock,buy,sell
fly,buy,home,rock,sell
Alright if you logically and the above lists the result would be
fly,buy
Because those 2 are the only same elements in those lists. Now how can i achieve this fastest run time way with C# 4.0 ? Thank you
c# , c#-4.0
You could use the Intersect method given by LINQ. For instance:
List<string> a = new List<string>() {"my","car","fly","surf","buy"};
List<string> b = new List<string>() {"house","home","car","fly","buy" };
var c = a.Intersect(b);
Gives car, fly, and buy. Repeat the intersection on c for the rest of your strings to get the full intersection.
You can use HashSet<T>:
IEnumerable<T> IntersectAll(IEnumerable<T> lists)
{
var set = new HashSet<T>(lists.First());
foreach (var other in lists.Skip(1))
{
set.IntersectWith(other);
}
return set;
}
List<List<string>> lists = //whatever
HashSet<string> set = new HashSet<string>(lists[0]);
for(int i = 1; i < lists.Count; i++)
{
set.IntersectWith(lists[i]);
}
Using linq you can use:
var intersection = lists.Aggregate((l1, l2) => l1.Intersect(l2).ToList());

Categories

Resources