How do I combine the contents of two lists? - c#

I have two List<int> instances. Now I want to combine them into a third list.
public List<int> oldItemarry1 // storing old item
{
get
{
return (List<int>)ViewState["oldItemarry1 "];
}
set
{
ViewState["oldItemarry1 "] = value;
}
}
public List<int> newItemarry1 // storing new item
{
get
{
return (List<int>)ViewState["newItemarry1 "];
}
set
{
ViewState["newItemarry1 "] = value;
}
}
public List<int> Itemarry1 // want to combine both the item
{
get
{
return (List<int>)ViewState["Itemarry1 "];
}
set
{
ViewState["Itemarry1 "] = value;
}
}
Please some one tell me how to do that?

LINQ has the Concat method:
return oldItemarry1.Concat(newItemarry1).ToList();
That just puts the list together. LINQ also has Intersect method, which will give you only items that exist in both lists and the Except method, which only gives you items that are present in either, but not both. The Union method give you all items between the two lists, but no duplicates like the Concat method.
If LINQ is not an option, you can just create a new list, add the items from each list to both via AddRange, and return that.
EDIT:
Since LINQ is not an option, you can do it a few ways:
Combine lists with all items, including duplicates:
var newList = new List<int>();
newList.AddRange(first);
newList.AddRange(second);
return newList
Combine without duplicate items
var existingItems = new HashSet<int>();
var newList = new List<int>();
existingItems.UnionWith(firstList);
existingItems.UnionWith(secondList);
newList.AddRange(existingItems);
return newList;
This of course assumes that you're using .NET 4.0, since that is when HashSet<T> was introduced. It's a shame you aren't using Linq, it really excels at things like this.

Use the Union method; it will exclude duplicates.
int[] combinedWithoutDups = oldItemarry1.Union(newItemarry1).ToArray();

You can combine two lists:
List<int> result = new List<int>();
result.AddRange(oldList1);
result.AddRange(oldList2);
The list result now has all the elements of both lists.

Here's one way to approach it:
public List<int> Itemarry1()
{
List<int> combinedItems = new List<int>();
combinedItems.AddRange(oldItemarray1);
combinedItems.AddRange(newItemarray1);
return combinedItems;
}

As a best practice, try to use IEnumerable rather than List when you can. Then, to make this work best you will want a read-only property:
public IEnumerable<int> Itemarry1 // want to combine both the item
{
get
{
return ((List<int>)ViewState["oldItemarry1 "]).Concat((List<int>)ViewState["Itemarry1"]);
}
}

If you need a point in time combination of two lists into a third list, Union and Concat are appropriate, as mentioned by others.
If you want a 'live' combination of the two lists (such that changes to the first and second list are automatically reflected in the 'combined' list) then you may want to look into Bindable LINQ or Obtics.

Related

How can I add an item to a list and return a new list

I was asked this question today:
How can I add an item to a list and return that list back?
The code for List<T>.Add(T) returns void. So you can't do something like this:
var list = new List<string>{"item1","item2"};
var newList = list.Add("item3");
This is related to using AutoMapper, although that part isn't particularly important.
One option is Linq, with Concat:
var list = new List<string>{"item1", "item2"};
var newList = list.Concat(new[] { "item3" }).ToList();
In typical Linq fashion, list stays the same, and newList contains all the items from list as well as the items in the new list, in this case just "item3".
You can skip the .ToList() to keep the IEnumerable<string> result if that fits your use case.
If you find yourself doing this often with individual items, you can use something like this extension method to pass them without the new[] { ... } syntax:
public static IEnumerable<T> ConcatItems<T>(this IEnumerable<T> source, params T[] items)
{
return source.Concat(items);
}
Because of the params array the earlier example becomes:
var list = new List<string>{"item1", "item2"};
var newList = list.ConcatItems("item3").ToList();
Make sure not to mix this up with Union, which removes duplicate items. (Searching for those duplicates is overhead that you probably don't want!)
The answer to this question was relatively simple:
var list = new List<string>(new List<string>{"item1","item2"}){"item3"};
List<T>() has a constructor that can take in IEnumerable<T> (MSDN). Additionally, you can use the object setter to put new items into the list.
So, for a more complicated example:
var originalList = new List<string>();
originalList.Add("item1");
originalList.Add("item2");
var newList = new List<string>(originalList){"item3"};
You can simply do :
List<string> list = new List<string>{"item1","item2"};
List<string> newList = null;
(newList = list.ToList()).Add("item3");
Or create your own extension method :
public static class Helper
{
public static List<T> MyAdd<T>(this List<T> collection, T item)
{
collection.Add(item);
return collection;
}
}
And use it :
List<string> list = new List<string>{"item1","item2"};
List<string> newList = list.MyAdd("item3"); // same object though
List<string> newList2 = newList.ToList().MyAdd("item4").MyAdd("item5"); // different object
One property of an ImmutableList<T> (and other similar data structures from System.Collections.Immutable) is that it doesn't mutate the original list, it returns another immutable list with the added value.
So doing this:
var originalImmutable = ImmutableList<int>.Create(1, 2);
var otherImmutable = originalImmutable.Add(3);
Will result in a shallow copied new list each time you call Add.
The most readable and maintainable solution is to copy the list and then add the item:
var list = new List<string>{"item1","item2"};
var newList = list.toList();
newList.Add("item3");
Seven years have passed since the question has been asked but Enumerable class now offers Prepend and Append methods that could be used in a straightforward fashion:
var list = new List<string>{"item1","item2"};
var newList = list.Append("item3").ToList();

is it possible to subset list of custom class objects based on a parameter of these objects? (without LINQ)

What I am trying to achieve in C# without using LINQ is to subset a list of custom-class objects based on the value of one of the parameters of these objects.
Let's say the declaration of my list is the following:
List<MyCustom> listofobj = new List<MyCustom>();
Also, assume that the custom-class object "MyCustom" can return two parameters: MyCustom.name and MyCustom.age
Is there a way trough which I can retrieve and save into a temporary new list (let's call it "templist") the subset of the original list (i.e. "listofobj") formed by all its MyCustom objects that have "age" parameter greater than 30? Thanks!
Sure. You can reinvent LINQ:
IEnumerable<MyCustom> WhereByAge(IEnumerable<MyCustom> source, int age)
{
foreach (MyCustom myCustom in source)
{
if (myCustom.Age > age)
{
yield return myCustom;
}
}
}
then:
List<MyCustom> filteredList = new List(WhereByAge(listofobj, 30));
But why? I strongly recommend that if you want LINQ-like behavior, just use LINQ.
This is how you get a subset of original list based on parameters without linq.
List<MyCustom> listofobj = new List<MyCustom>();
List<MyCustom> templist = new List<MyCustom>();
foreach(var obj in listofobj)
{
if(obj.Age > 30)
{
templist.Add(obj);
}
}
You can also use this Linq.
templist = listofobj.Where(obj => obj.Age > 30).ToList();
Linq is slower than a normal code in general. but this should not be problem if this is not hot path in your code. performance difference is negligible.

Accept "params" which are lists themselves?

I'm trying to write a method for a project which takes any number of lists as parameters, and returns a new list containing terms which ALL of those lists share. I have functional code, but I'd much prefer to use the params keyword rather than having to create a list of lists which holds all the lists I want to compare.
static List<T> Shared<T>(List<T> first, List<T> second)
{
List<T> result = new List<T>();
foreach (T item in first)
if (second.Contains(item) && !result.Contains(item)) result.Add(item);
return result;
}
static List<T> Shared<T>(List<List<T>> lists)
{
List<T> result = lists.First();
foreach (List<T> list in lists.Skip(1))
{
result = Shared<T>(result, list);
}
return result;
}
Is my current code, which works fine comparing two lists, but in order to compare more than two lists I have to either create a new list like:
List<int> nums1 = new List<int> { 1, 2, 3, 4, 5, 6 };
List<int> nums2 = new List<int> { 1, 2, 3 };
List<int> nums3 = new List<int> { 6, 5, 3, 2 };
List<int> listOfLists = Shared<int>(new List<List<int>> {nums1, nums2, nums3});
foreach (int item in listOfLists)
Console.WriteLine(item);
//Writes 2 and 3
etc. I would really wish to just be able to use Shared(list1, list2, list3, list4...) instead, even if this code is already somewhat functional. Currently any attempts to use a params version complains that "No overload for method 'Shared' takes N arguments"
Also I know my code could probably be done more efficiently, so I'd be glad to see suggestions on that too but primarily I need to get my head around why using params isn't working - if it's even possible.
Are you looking for this?
static List<T> Shared<T>(params List<T>[] lists)
The params parameter must always have an array type, but it can be an array of Lists.
It can be done quiet easily:
using System.Linq;
// ..
static List<T> Shared<T>(params List<T>[] lists)
{
if (lists == null)
{
throw new ArgumentNullException("lists");
}
return Shared(lists.ToList());
}
Building on the response of #Selman22 who proposed the method signature, you could alternatively use this LINQ query, to achieve the desired result.
static List<T> Shared<T>(params List<T>[] lists)
{
return
lists.Skip(1).Aggregate( // Skip first array item, because we use it as a seed anyway
lists.FirstOrDefault(), // Seed the accumulator with first item in the array
(accumulator, currentItem) => accumulator.Intersect(currentItem).ToList()); // Intersect each item with the previous results
}
We skip the first item that is being used as the seed for the accumulator, and do an intersect with the accumulator for each item in the given params array, since only the items that are contained in ALL the lists are kept in the accumulator result.
To test it out, you can use
Shared(nums1, nums2, nums3).ForEach(r => Console.WriteLine(r));

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

Using C#, what's an efficient way to compare/merge two generic lists of the same type?

If I have two generic lists, List, and I want to merge all the unique Place objects into one List, based on the Place.Id property, what's a good method of doing this efficiently?
One list will always contain 50, the other list could contain significantly more.
result = list1.Union(list2, new ElementComparer());
You need to create ElementComparer to implement IEqualityComparer. E.g. see this
If you want to avoid having to define your own ElementComparer and just use lambda expressions, you can try the following:
List<Place> listOne = /* whatever */;
List<Place> listTwo = /* whatever */;
List<Place> listMerge = listOne.Concat(
listTwo.Where(p1 =>
!listOne.Any(p2 => p1.Id == p2.Id)
)
).ToList();
Essentially this will just concatenate the Enumerable listOne with the set of all elements in listTwo such that the elements are not in the intersection between listOne and listTwo.
Enumerable.Distinct Method
Note: .NET 3.5 & above.
If you want to emphasize efficiency, I suggest you write a small method to do the merge yourself:
List<Place> constantList;//always contains 50 elements. no duplicate elements
List<Place> targetList;
List<Place> result;
Dictionary<int, Place> dict;
for(var p in constantList)
dict.Put(p.Id,p);
result.AddRange(constantList);
for(var p in targetList)
{
if(!dict.Contains(p.Id))
result.Add(p)
}
If speed is what you need, you need to compare using a Hashing mechanism. What I would do is maintain a Hashset of the ids that you have already read and then add the elements to the result if the id hasn't been read yet. You can do this for as many lists as you want and can return an IEnumerable instead of a list if you want to start consuming before the merge is over.
public IEnumerable<Place> Merge(params List<Place>[] lists)
{
HashSet<int> _ids = new HashSet<int>();
foreach(List<Place> list in lists)
{
foreach(Place place in list)
{
if (!_ids.Contains(place.Id))
{
_ids.Add(place.Id);
yield return place;
}
}
}
}
The fact that one list has 50 elements and the other one many more has no implication. Unless you know that the lists are ordered...

Categories

Resources