Take next item from list while iterating with another list - c#

I have two list
List<string> listA;
List<string> listB;
How to get next item of listA when im iterating with listB? Pseudocode:
List<dynamic> listC = new List<dynamic>();
foreach (var elementA in listA)
{
listC.Add(new
{
a: elementA,
b: listB.TakeNextItem() // how to achive this?
});
}

You could use Enumerable.Zip:
var listC = listA
.Zip(listB, (a, b) => new { a, b })
.ToList();
This iterates over both lists and projects items into a new list.
It also statically types your listC variable, rather than using dynamic.

You could use a for loop instead of a foreach loop and then use the current index to access both listA and listB at the same time.
List<dynamic> listC = new List<dynamic>();
// When listA Count is as bigger as listB don't execute for-loop
if (listA.Count > listB.Count) {
return;
}
for (int i = 0; i < listA.Count; i++) {
listC.Add(new {
a = listA[i],
b = listB[i]
});
}

Related

Swapping elements between 2 hashsets c#

If I have 2 hashsets of size 5, how can I take x items from the first hashset and swap them with x items from the second one ?
For example :
HashSet 1 has elements = {a , b, c , d ,e}
HashSet 2 has elements = {r , s ,t ,u , w}
After the swap I would like to obtain:
HashSet 1 = {r, s , c ,d e}
HashSet 2 = {a, b, t , u ,w}
I don't need a speficic order.
Perhaps:
HashSet<string> hash1 = new HashSet<string>() { "A1", "B1", "C1", "D1" };
HashSet<string> hash2 = new HashSet<string>() { "A2", "B2", "C2", "D2" };
var firstThreeInOne = hash1.Take(3).ToList();
var firstThreeInTwo = hash2.Take(3).ToList();
foreach (string str in firstThreeInOne)
hash1.Remove(str);
foreach (string str in firstThreeInTwo)
hash2.Remove(str);
foreach (string str in firstThreeInTwo)
hash1.Add(str);
foreach (string str in firstThreeInOne)
hash2.Add(str);
Test:
Console.WriteLine(string.Join(",", hash1)); // C2,B2,A2,D1
Console.WriteLine(string.Join(",", hash2)); // C1,B1,A1,D2
But note that a HashSet does not guarantee insertion order. It is simply not an ordered collection.
MSDN mentions that explicitly:
The HashSet<T> class provides high-performance set operations. A set
is a collection that contains no duplicate elements, and whose
elements are in no particular order.
You can't unless you will implement hashset with ordering.
HashSet class of CLR has not ordering, and you can't get "first N" elements
As DarkFalcon and others said the HashSet per definition has no order and therefor there are no first x elements in it.
BUT as with every collection you can get elements with the ElementAt method in some kind of order.
Be aware that you cannot know WHICH of the elements are counted as the first ones...
void Main()
{
var hashSet1 = new HashSet<int>();
hashSet1.Add(1);
hashSet1.Add(2);
hashSet1.Add(3);
hashSet1.Add(4);
hashSet1.Add(5);
var hashSet2 = new HashSet<int>();
hashSet2.Add(6);
hashSet2.Add(7);
hashSet2.Add(8);
hashSet2.Add(9);
hashSet2.Add(0);
SwapHashSets(hashSet1, hashSet2, 3);
}
private List<int> GetXValuesFromHashSet(HashSet<int> hashSet, int count)
{
var list = new List<int>();
for (var i = 0; i < count; i++)
{
list.Add(hashSet.ElementAt(i));
}
return list;
}
private void SwapHashSets(HashSet<int> hashSet1, HashSet<int> hashSet2, int count )
{
var list1 = GetXValuesFromHashSet(hashSet1, count);
var list2 = GetXValuesFromHashSet(hashSet2, count);
foreach (var value in list1)
{
hashSet1.Remove(value);
}
foreach (var value in list2)
{
hashSet2.Remove(value);
}
foreach (var value in list1)
{
hashSet2.Add(value);
}
foreach (var value in list2)
{
hashSet1.Add(value);
}
}

What is the correct way to sort List <string> using C#?

I have LIST1 <> and LIST2 <> and like to compare these two lists. Followings are my conditions..
1-If LIST1 and LIST2 have the same items than add same items to LIST3
2-If LIST1 doesnt contain LIST2 items than add different items to LIST4
3-if LIST2 doesnt contain LIST1 items than add different items to LIST5
lets say my result is like below depends on the conditions;
LIST1<string> = A,B,C,D
LIST2<string> = A,K,F,C
LIST3<string> = A,C
LIST4<string> = B,D
LIST5<string> = K,F
here is my code;
foreach (string src in LIST1)
{
foreach (string trg in LIST2)
{
if (LIST1.ToString() == LIST2.ToString())
{
LIST3.Add(LIST1.ToString());
}
else
{
LIST4.Clear();
foreach (string l3 in LIST1)
{
if (!LIST2.Contains(l3))
LIST4.Add(l3);
}
LIST5.Clear();
foreach (string l4 in LIST2)
{
if (!LIST1.Contains(l4))
{
LIST5.Add(l4);
}
}
}
}
}
A quick way to do this would be:
var list3 = list1.Intersect(list2).ToList();
var list4 = list1.Except(list2).ToList();
var list5 = list2.Except(list1).ToList();
Update: If you have to do with larger lists (and/or have to write this in multiple places), you can write an extension method like below:
public static Tuple<IEnumerable<T>, IEnumerable<T>, IEnumerable<T>> Diff<T>(
this IEnumerable<T> first, IEnumerable<T> second)
{
var intersection = new List<T>();
var onlyInFirst = new HashSet<T>();
var onlyInSecond = new HashSet<T>(second);
foreach (var item in first)
{
if (onlyInSecond.Remove(item)) intersection.Add(item);
else onlyInFirst.Add(item);
}
return Tuple.Create<IEnumerable<T>, IEnumerable<T>, IEnumerable<T>>
(intersection, onlyInFirst, onlyInSecond);
}
This method returns a tuple of three IEnumerable<T>s representing the set of intersection, set of items only in the first collection, and set of items only in the second collection; respectively.
Usage:
var list1 = new[] { "A", "B", "C", "D" };
var list2 = new[] { "A", "K", "F", "C" };
var diff = list1.Diff(list2);
// diff.Item1 = A,C (intersection)
// diff.Item2 = B,D (only in first)
// diff.Item3 = K,F (only in second)
Not sure what this has to do with sorting, but here's Linq statements for each condition:
List3 = List1.Intersect(List2).ToList();
List4 = List1.Where(l1 => !List2.Any(l2 => l2 == l1)).ToList();
List5 = List2.Where(l2 => !List1.Any(l1 => l2 == l1)).ToList();
as pointed out in comments Except will work too:
List4 = List1.Except(List2).ToList();
List5 = List2.Except(List1).ToList();

Manipulation on all list items options for n lists in c#

I'd like to split my data to lists by an attribute's value and check all the combination options between the lists' items.
My problems are that I don't know how many list I'll get and if there is a better way to do that beside this way:
var a = Data.Descendants("value").Where(x => x.Attribute("v").Value == "1").ToList();
var b = Data.Descendants("value").Where(x => x.Attribute("v").Value == "2").ToList();
var c = Data.Descendants("value").Where(x => x.Attribute("v").Value == "3").ToList();
foreach (var tempA in a)
{
foreach (var tempB in b)
{
foreach (var tempC in c)
{
DO SOMETHING;
}
}
}
EDIT:
I'd like to check my items from one data source (var items = new List<string>{"1","1","2","3","2","1","3","3","2"})
Now I'd like to split this list to 3 lists (list a = "1","1","1" - list b = "2","2","2" - list c = "3","3","3")
In this step what I'm trying to do is to check all the combination from one item in one list to the other items in the other lists.
a[0] with b[0] c[0]
a[0] with b[0] c[1]
a[0] with b[0] c[2]
a[0] with b[1] c[0]
.
.
b[1] with a[2] c[2]
.
.
Thanks!
Could you try using the LINQ GroupBy method? Some examples are here:
LINQ GroupBy examples
You can use GroupBy to group your elements. Then you can create combinations using Linq.
var grouping = Data.Descendants("value")
.GroupBy(x => x.Attribute("v").Value);
var combinations grouping.SelectMany(x =>
grouping.Select(y =>
new { Group = x, Combination = y }));
foreach(var c in combinations)
{
//Do Something
}
e.g.
public class Pair
{
public string A { get; set; }
public string B { get; set; }
}
var pairs = new List<Pair>();
pairs.Add(new Pair { A = "1", B = "2" });
pairs.Add(new Pair { A = "1", B = "3" });
pairs.Add(new Pair { A = "1", B = "4" });
pairs.Add(new Pair { A = "2", B = "1" });
pairs.Add(new Pair { A = "2", B = "2" });
pairs.Add(new Pair { A = "2", B = "3" });
var grouping = pairs.GroupBy(x => x.A);
var combinations = grouping.SelectMany(x =>
grouping.Select(y =>
new { Group = x, Combination = y }));
You can do this,following the line of thinking of romoku and chrisC
//new list of lists to hold new information.
List<List<Descendants>> NewList = new List<List<Descendants>>();
foreach (var item in Data.Descendants.GroupBy(x => x.Attribute("v").Value))
{
NewList.Add(item.ToList());
}
For your new edit list of Strings this will do it
List<List<string>> NewList = new List<List<string>>();
foreach (var item in OriginalList.GroupBy(x => x))
{
NewList.Add(item.ToList());
}

How to combine multiple lists with custom sequence

Not sure if there's a algorithm to describe this problem but are there any elegant methods to combine the list in a custom sequence. For example:
List<string> list1 = new List<string>();
List<string> list2 = new List<string>();
List<string> list3 = new List<string>();
list1.Add("a");
list1.Add("b");
list1.Add("c");
list2.Add("d");
list2.Add("e");
list2.Add("f");
list3.Add("g");
list3.Add("h");
list3.Add("i");
List<string> combined = new List<string>();
I would like the contents of combined to contain a sequence as follows:
a //First record in list1
d //First record in list2
g //First record in list3
b //Second record in list1
e //Second record in list2
h //Second record in list3
c //Third record in list1
f //Third record in list2
i //Third record in list3
The number of records in each list may not be equal.
EDIT
When the number of records in each list may not be equal i mean:
List<string> list1 = new List<string>();
List<string> list2 = new List<string>();
List<string> list3 = new List<string>();
list1.Add("a");
list2.Add("b");
list2.Add("c");
list3.Add("d");
list3.Add("e");
list3.Add("f");
List<string> combined = new List<string>();
Expected results:
a //First record in list1
b //First record in list2
d //First record in list3
c //Second record in list2
e //Second record in list3
f //Third record in list3
Not sure if there's a name. Merging? Splicing? But the code is easy.
var lists = new [] { list1, list2, list3 };
var combined = new List<string>(lists.Sum(l => l.Count));
for (var i = 0; i < lists.Max(l => l.Count); i++)
{
foreach (var list in lists)
{
if (i < list.Count)
combined.Add (list[i])
}
}
int MaxCount = List1.Count; //Or whatever the highest list count.
for (int i = 0; i < MaxCount; i++)
{
if( list1.Count > i)
combined.Add(list1[i]);
if( list2.Count > i)
combined.Add(list2[i]);
if( list3.Count > i)
combined.Add(list3[i]);
}
Unfortunately there are no built in function for it.
You should loop each list and add it to a new custom list.
Example:
List<string> result = new List<string>();
int listLength = Math.Max(list1.Count, Math.Max(list2.Count, list3.Count)); // get the largest list length
for(int index = 0; index < listLength; i++){
if(list1.Count > index) result.Add(list1[index);
if(list2.Count > index) result.Add(list3[index);
if(list3.Count > index) result.Add(list3[index);
}
You could use this generic Merge<T> function:
public static IEnumerable<T> Merge<T>(params List<T>[] lists)
{
var max = lists.Max(list => list.Count());
for (int i = 0; i < max; i++)
{
foreach (var list in lists)
{
if (i < list.Count)
{
yield return list[i];
}
}
}
}
Example usage:
var merged = Merge(list1, list2, list3).ToList();
A quick LINQPad example:
void Main()
{
List<string> list1 = new List<string>();
List<string> list2 = new List<string>();
List<string> list3 = new List<string>();
list1.Add("a");
list1.Add("b");
list1.Add("c");
list2.Add("d");
list2.Add("e");
list2.Add("f");
list3.Add("g");
list3.Add("h");
list3.Add("i");
Merge(new[] { list1, list2, list3}, (c1, c2) => c1 + c2).SelectMany(s => s).Dump();
}
IEnumerable<T> Merge<T>(IEnumerable<IEnumerable<T>> sources, Func<T, T, T> combine)
{
return sources.Aggregate((s1, s2) => s1.Zip(s2, combine));
}
The result is an IEnumerable<char> but this is simple enough to convert into a List<string> if necessary.
You can either use Concate() or AddRange, see this thread for more info about the difference between these methods

Adding Lists Together

I have multiple lists of strings, IList<string>, that I want to consolidate in one list showing distinct string and count for each item (like a dictionary). what is the most efficient way to do this?
LINQ (certainly the most efficient in terms of code to type and maintain; the overall performance will be about the same as any other approach):
if the lists are in separate variables:
var qry = from s in listA.Concat(listB).Concat(listC) // etc
group s by s into tmp
select new { Item = tmp.Key, Count = tmp.Count() };
if the lists are all in a parent list (of lists):
var qry = from list in lists
from s in list
group s by s into tmp
select new { Item = tmp.Key, Count = tmp.Count() };
Then if you really want a list:
var resultList = qry.ToList();
Dictionary<string, int> count = new Dictionary<string, int>();
foreach(IList<int> list in lists)
foreach(int item in list) {
int value;
if (count.TryGetValue(item, out value))
count[item] = value + 1;
else
count[item] = 1;
}
List<List<string>> source = GetLists();
//
Dictionary<string, int> result = source
.SelectMany(sublist => sublist)
.GroupBy(s => s)
.ToDictionary(g => g.Key, g => g.Count())

Categories