Convert List<List<T>> into List<T> in C# - c#

I have a List<List<int>>. I would like to convert it into a List<int> where each int is unique. I was wondering if anyone had an elegant solution to this using LINQ.
I would like to be able to use the Union method but it creates a new List<> everytime. So I'd like to avoid doing something like this:
List<int> allInts = new List<int>();
foreach(List<int> list in listOfLists)
allInts = new List<int>(allInts.Union(list));
Any suggestions?
Thanks!

List<List<int>> l = new List<List<int>>();
l.Add(new List<int> { 1, 2, 3, 4, 5, 6});
l.Add(new List<int> { 4, 5, 6, 7, 8, 9 });
l.Add(new List<int> { 8, 9, 10, 11, 12, 13 });
var result = (from e in l
from e2 in e
select e2).Distinct();
Update 09.2013
But these days I would actually write it as
var result2 = l.SelectMany(i => i).Distinct();

List<int> result = listOfLists
.SelectMany(list => list)
.Distinct()
.ToList();

How about:
HashSet<int> set = new HashSet<int>();
foreach (List<int> list in listOfLists)
{
set.UnionWith(list);
}
return set.ToList();

Related

Get common elements with index from two list C#

I have Two lists of type list<int> and i know we can find the common elements between two lists. But is there any way to get common elements and corresponding indexes of common elements in Intersected list or i need to go across each elements find the indexes.
LINQ has operations to project a sequence using indexes, but this isn't built into the query expression syntax, so you have to use "regular" extension method calls to start with. After that it's fairly easy, although probably just as simple not using LINQ, to be honest:
var pairs1 = list1.Select((value, index) => new { value, index });
var pairs2 = list2.Select((value, index) => new { value, index });
var matches = from pair1 in pairs1
join pair2 in pairs2 on pair1.value equals pair2.value
select new
{
Value = pair1.value,
Index1 = pair1.index,
Index2 = pair2.index
};
(You could use from pair2 in pairs2 where pair1.value == pair2.value if you'd prefer...)
Or non-LINQ (using Tuple<,,> for simplicity; other options are feasible):
var results = new List<Tuple<int, int, int>>();
for (int index1 = 0; index1 < list1.Count; index1++)
{
for (int index2 = 0; index2 < list2.Count; index2++)
{
if (list1[index1] == list2[index2])
{
results.Add(Tuple.Of(list1[index1], index1, index2);
}
}
}
Note that unlike a regular intersection operation, both of these can give you multiple results for the same value - because there can be multiple index pairs. For example, with lists of { 1, 2 } and {2, 2, 0}, you'd have tuples of (value=2,index1=1,index2=0), (value=2,index1=1,index2=1).
try below code
List<int> lstA = new List<int>() { 10, 2, 7, 9, 13, 21, 17 };
List<int> lstB = new List<int>() { 2, 10, 7, 21, 13, 9, 17 };
var lstA_Temp = lstA.Select((value, index) => new { index, value }).ToList();
var lstB_Temp = lstB.Select((value, index) => new { index, value }).ToList();
List<int> result = (from A in lstA_Temp from B in lstB_Temp
where A.index == B.index where A.value == B.value
select A.value).ToList();
you can also do this thing without linq see below logic
List<int> lstA = new List<int>() { 10, 2, 7, 9, 13, 21, 17 };
List<int> lstB = new List<int>() { 2, 10, 7, 21, 13, 9, 17 };
List<int> lstResult = new List<int>();
for (int i = 0; i < lstA.Count; i++)
{
if (lstA[i] == lstB[i])
lstResult.Add(lstA[i]);
}

How to Get the longest match found in number of sets, order is important

I need to find a way to return the longest match found in number of sets/lists (values returns only once) when the order of items is important.
the list is not cyclic.
A match is a sequence of values that exists in all the lists and maintains the same order of elements in all the lists.
e.g. 1:
List<int> list1 = new List<int> { 1, 2, 3, 4, 7, 9 };
List<int> list2 = new List<int> { 1, 2, 5, 6, 3, 4, 7, 9 };
List<int> list3 = new List<int> { 1, 2, 3, 6, 8, 9 };
List<int> list4 = new List<int> { 1, 2, 5, 6, 8, 9 };
result { 1, 2 }
e.g. 2:
List<int> list1 = new List<int> { 2, 3, 6, 8, 1, 18 };
List<int> list2 = new List<int> { 2, 3, 4, 6, 8, 1, 18, 19, 17, 14 };
List<int> list3 = new List<int> { 2, 5, 6, 8, 1, 18, 16, 13, 14 };
List<int> list4 = new List<int> { 2, 6, 8, 1, 18, 19, 17, 14 };
result { 6, 8, 1, 18 }
The match doesn't have to be found at the beginning or at the end and can be on any part of any list.
I hope that I explained my problem good enough :)
Thanks!
You can build a map from pairs of ints to a count of how many of the lists they appear adjacent in.
Pseudo-code:
For each list L {
For each adjacent pair (x, y) in L {
Counts[x, y] += 1
}
}
Now you can iterate through the first list (or the shortest list), and find the longest run such that each adjacent pair (x, y) in the run with Counts[x, y] showing that the pair appears in every list.
Pseudo-code:
run = []
best_run = []
For x in L[0] {
if len(run) is zero or Counts[run[len(run)-1], x] == number of lists {
run = run + x
} else {
run = [x]
}
if run is longer than best_run {
best_run = run
}
}
This works given the assumption in the question that no integer appears twice in the same list.
This algorithm runs in O(N) time, where N is the sum of the lengths of all the lists.
Here's my approach.
First I need a way to compare lists:
public class ListCompare<T> : IEqualityComparer<List<T>>
{
public bool Equals(List<T> left, List<T> right)
{
return left.SequenceEqual(right);
}
public int GetHashCode(List<T> list)
{
return list.Aggregate(0, (a, t) => a ^ t.GetHashCode());
}
}
Next a method to produce all subsequences of a source list:
Func<List<int>, IEnumerable<List<int>>> subsequences = xs =>
from s in Enumerable.Range(0, xs.Count)
from t in Enumerable.Range(1, xs.Count - s)
select xs.Skip(s).Take(t).ToList();
Now I can create a list of lists:
var lists = new [] { list1, list2, list3, list4, };
Finally a query that pulls it all together:
var answer =
lists
.Skip(1)
.Aggregate(
subsequences(lists.First()),
(a, l) => a.Intersect(subsequences(l), new ListCompare<int>()))
.OrderByDescending(x => x.Count)
.FirstOrDefault();
Given the sample data provided in the question this produces the expected results.
First generate an ordered combination of int from the shortest list
Compare the lists other than shortest list with the combination. For easy comparison of lists I just convert to string and use string.Contains()
Return immediately if find the match as the items left are next order or the shorter one.
public static List<int> GetLongestMatch(params List<int>[] all)
{
var shortest = all.Where(i => i.Count == all.Select(j => j.Count).Min()).First();
var permutations = (from length in Enumerable.Range(1, shortest.Count)
orderby length descending
from count in Enumerable.Range(1, shortest.Count - length + 1)
select shortest.Skip(count - 1).Take(length).ToList())
.ToList();
Func<List<int>, string> stringfy = (list) => { return string.Join(",", list.Select(i => i.ToString()).ToArray()); };
foreach (var item in permutations)
{
Debug.WriteLine(string.Join(", ", item.Select(i => i.ToString()).ToArray()));
if (all.All(list => stringfy(list).Contains(stringfy(item))))
{
Debug.WriteLine("Matched, skip process and return");
return item;
}
}
return new List<int>();
}
Usage
var result = GetLongestMatch(list1, list2, list3, list4);
Result
2, 3, 6, 8, 1, 18
2, 3, 6, 8, 1
3, 6, 8, 1, 18
2, 3, 6, 8
3, 6, 8, 1
6, 8, 1, 18
Matched, skip process and return

To find the top 3 maximum repeated numbers in a integer array

I want to find the top 3 maximum repeated numbers in a Integer array?
Below is the piece of code which I have tried but I couldn't find the desired result:
static void Main(string[] args)
{
int[,] numbers = {
{1, 2, 0, 6 },
{5, 6, 7, 0 },
{9, 3, 6, 2 },
{6, 4, 8, 1 }
};
int count = 0;
List<int> checkedNumbers = new List<int>();
foreach (int t in numbers)
{
if (!checkedNumbers.Contains(t))
{
foreach (int m in numbers)
{
if (m == t)
{
count++;
}
}
Console.WriteLine("Number {0} is Repeated {1} Times ", t, count);
count = 0;
checkedNumbers.Add(t);
}
}
Console.ReadLine();
}
You can use GroupBy from LINQ then OrderByDescending based on count in each group:
var result = list.GroupBy(i => i)
.OrderByDescending(g => g.Count())
.Select(g => g.Key)
.Take(3);
Edit: With your code, you can use OfType to flatten your matrix then use the code above:
int[,] numbers = {
{1, 2, 0, 6 },
{5, 6, 7, 0 },
{9, 3, 6, 2 },
{6, 4, 8, 1 }
};
var list = numbers.OfType<int>();
int[] numbers = {1, 2, 3, 5, 6, 32, 2, 4, 42, 2, 4, 4, 5, 6, 3, 4};
var counts = new Dictionary<int, int>();
foreach (var number in numbers)
{
counts[number] = counts[number] + 1;
}
var top3 = counts.OrderByDescending(x => x.Value).Select(x => x.Key).Take(3);
Hint:
You can do this with the help of LINQ.
This is the code to find most frequest occuring element:-
List<int> list = new List<int>() { 1,1,2,2,3,4,5 };
// group by value and count frequency
var query = from i in list
group i by i into g
select new {g.Key, Count = g.Count()};
// compute the maximum frequency
int frequency = query.Max(g => g.Count);
// find the values with that frequency
IEnumerable<int> modes = query
.Where(g => g.Count == frequency)
.Select(g => g.Key);
// dump to console
foreach(var mode in modes) {
Console.WriteLine(mode);
}
In the same manner you can find the other two also.
I see that none of the existing answers provide an explanation, so I will try to explain.
What you need to do is to count how many times each item appears in the array. To do that, there are various methods (dictionaries, linq etc). Probably it would be easiest to use a dictionary which contains the number, and how may times it appeared:
int numbers[] = {1, 3, 6, 10, 9, 3, 3, 1, 10} ;
Dictionary<int, int> dic = new Dictionary<int, int>();
Now iterate through every element in numbers, and add it to the dictionary. If it was already added, simply increase the count value.
foreach (var i in numbers)
{
dic[i]++; // Same as dic[i] = dic[i]+1;
}
The dictionary will automatically adds a new item if it doesn't exist, so we can simply do dic[i]++;
Next, we need to get the highest 3 values. Again, there are many ways to do this, but the easiest one would be to sort it.
var sorted_dic = dic.OrderByDescending(x => x.Value);
Now the first 3 items in sorted_dic are going to be the 3 values you are looking for.
There are various methods to get only these 3, for example using the Take method:
var first_3 = sorted_dic.Take(3);
Now you can iterate through these 3 values, and for example print them on the screen:
foreach (var i in first_3)
{
Console.Write("{0} appeared {1} times.", i.Key, i.Value);
}

Conversion of System.Array to List

Last night I had dream that the following was impossible. But in the same dream, someone from SO told me otherwise. Hence I would like to know if it it possible to convert System.Array to List
Array ints = Array.CreateInstance(typeof(int), 5);
ints.SetValue(10, 0);
ints.SetValue(20, 1);
ints.SetValue(10, 2);
ints.SetValue(34, 3);
ints.SetValue(113, 4);
to
List<int> lst = ints.OfType<int>(); // not working
Save yourself some pain...
using System.Linq;
int[] ints = new [] { 10, 20, 10, 34, 113 };
List<int> lst = ints.OfType<int>().ToList(); // this isn't going to be fast.
Can also just...
List<int> lst = new List<int> { 10, 20, 10, 34, 113 };
or...
List<int> lst = new List<int>();
lst.Add(10);
lst.Add(20);
lst.Add(10);
lst.Add(34);
lst.Add(113);
or...
List<int> lst = new List<int>(new int[] { 10, 20, 10, 34, 113 });
or...
var lst = new List<int>();
lst.AddRange(new int[] { 10, 20, 10, 34, 113 });
There is also a constructor overload for List that will work... But I guess this would required a strong typed array.
//public List(IEnumerable<T> collection)
var intArray = new[] { 1, 2, 3, 4, 5 };
var list = new List<int>(intArray);
... for Array class
var intArray = Array.CreateInstance(typeof(int), 5);
for (int i = 0; i < 5; i++)
intArray.SetValue(i, i);
var list = new List<int>((int[])intArray);
Interestingly no one answers the question, OP isn't using a strongly typed int[] but an Array.
You have to cast the Array to what it actually is, an int[], then you can use ToList:
List<int> intList = ((int[])ints).ToList();
Note that Enumerable.ToList calls the list constructor that first checks if the argument can be casted to ICollection<T>(which an array implements), then it will use the more efficient ICollection<T>.CopyTo method instead of enumerating the sequence.
The simplest method is:
int[] ints = new [] { 10, 20, 10, 34, 113 };
List<int> lst = ints.ToList();
or
List<int> lst = new List<int>();
lst.AddRange(ints);
In the case you want to return an array of enums as a list you can do the following.
using System.Linq;
public List<DayOfWeek> DaysOfWeek
{
get
{
return Enum.GetValues(typeof(DayOfWeek))
.OfType<DayOfWeek>()
.ToList();
}
}
in vb.net just do this
mylist.addrange(intsArray)
or
Dim mylist As New List(Of Integer)(intsArray)
You can do like this basically:
int[] ints = new[] { 10, 20, 10, 34, 113 };
this is your array, and than you can call your new list like this:
var newList = new List<int>(ints);
You can do this for complex object too.
You can just give it try to your code:
Array ints = Array.CreateInstance(typeof(int), 5);
ints.SetValue(10, 0);
ints.SetValue(20, 1);
ints.SetValue(10, 2);
ints.SetValue(34, 3);
ints.SetValue(113, 4);
int[] anyVariable=(int[])ints;
Then you can just use the anyVariable as your code.
I know two methods:
List<int> myList1 = new List<int>(myArray);
Or,
List<int> myList2 = myArray.ToList();
I'm assuming you know about data types and will change the types as you please.
Just use the existing method.. .ToList();
List<int> listArray = array.ToList();
KISS(KEEP IT SIMPLE SIR)
I hope this is helpful.
enum TESTENUM
{
T1 = 0,
T2 = 1,
T3 = 2,
T4 = 3
}
get string value
string enumValueString = "T1";
List<string> stringValueList = typeof(TESTENUM).GetEnumValues().Cast<object>().Select(m =>
Convert.ToString(m)
).ToList();
if(!stringValueList.Exists(m => m == enumValueString))
{
throw new Exception("cannot find type");
}
TESTENUM testEnumValueConvertString;
Enum.TryParse<TESTENUM>(enumValueString, out testEnumValueConvertString);
get integer value
int enumValueInt = 1;
List<int> enumValueIntList = typeof(TESTENUM).GetEnumValues().Cast<object>().Select(m =>
Convert.ToInt32(m)
).ToList();
if(!enumValueIntList.Exists(m => m == enumValueInt))
{
throw new Exception("cannot find type");
}
TESTENUM testEnumValueConvertInt;
Enum.TryParse<TESTENUM>(enumValueString, out testEnumValueConvertInt);

C# Creating an array of arrays

I'm trying to create an array of arrays that will be using repeated data, something like below:
int[] list1 = new int[4] { 1, 2, 3, 4 };
int[] list2 = new int[4] { 5, 6, 7, 8 };
int[] list3 = new int[4] { 1, 3, 2, 1 };
int[] list4 = new int[4] { 5, 4, 3, 2 };
int[,] lists = new int[4, 4] { list1 , list2 , list3 , list4 };
I can't get it to work and so I'm wondering if I'm approaching this wrong.
What I'm attempting to do is create some sort of method to create a long list of the values so I can process them in a specific order, repeatedly. Something like,
int[,] lists = new int[90,4] { list1, list1, list3, list1, list2, (and so on)};
for (int i = 0; i < 90; ++i) {
doStuff(lists[i]);
}
and have the arrays passed to doStuff() in order. Am I going about this entirely wrong, or am I missing something for creating the array of arrays?
What you need to do is this:
int[] list1 = new int[4] { 1, 2, 3, 4};
int[] list2 = new int[4] { 5, 6, 7, 8};
int[] list3 = new int[4] { 1, 3, 2, 1 };
int[] list4 = new int[4] { 5, 4, 3, 2 };
int[][] lists = new int[][] { list1 , list2 , list3 , list4 };
Another alternative would be to create a List<int[]> type:
List<int[]> data=new List<int[]>(){list1,list2,list3,list4};
The problem is that you are attempting to define the elements in lists to multiple lists (not multiple ints as is defined). You should be defining lists like this.
int[,] list = new int[4,4] {
{1,2,3,4},
{5,6,7,8},
{1,3,2,1},
{5,4,3,2}};
You could also do
int[] list1 = new int[4] { 1, 2, 3, 4};
int[] list2 = new int[4] { 5, 6, 7, 8};
int[] list3 = new int[4] { 1, 3, 2, 1 };
int[] list4 = new int[4] { 5, 4, 3, 2 };
int[,] lists = new int[4,4] {
{list1[0],list1[1],list1[2],list1[3]},
{list2[0],list2[1],list2[2],list2[3]},
etc...};
I think you may be looking for Jagged Arrays, which are different from multi-dimensional arrays (as you are using in your example) in C#. Converting the arrays in your declarations to jagged arrays should make it work. However, you'll still need to use two loops to iterate over all the items in the 2D jagged array.
This loops vertically but might work for you.
int rtn = 0;
foreach(int[] L in lists){
for(int i = 0; i<L.Length;i++){
rtn = L[i];
//Do something with rtn
}
}
The following will give you an array in the iterator variable of foreach
int[][] ar =
{
new []{ 50, 50, 1 },
new []{ 80, 40, 2 },
new []{ 10, 60, 3 },
new []{ 51, 38, 4 },
new []{ 48, 38, 5 }
};

Categories

Resources