C# how get maximum value from list of lists - c#

I have a list of lists that I have created from a "tab" delimited string. Instead of a 2d array i use list of lists as I dont know the size to create the array.
It will be something like,
0 0
16.0000 0
15.0000 15.0000
0 15.0000
2.7217 5.6904
3.7217 5.6904
I now want to find the maximum and minimum from each of the columns.
So if you take the above example,
maximum would be : 16.0000 15.0000
and minimum would be : 0 0
for (int i = 0; i < size[0]; i++)
{
// Create size[0] x size[1] array
obstVertex.Add(new List<double>());
for (int y = 0; y < size[1]; y++)
{
obstVertex[i].Add(Convert.ToDouble(split[i+(y*size[0])]));
}
}
How can I find the maximum or the minimum value using linq ???
Thanks in advance

List<List<double>> myList;
myList.Add(new List(new double[] { 0, 16, 15, 0, 2.7217, 3.7217 }));
myList.Add(new List(new double[] { 0, 0, 15, 15, 5.6904, 5.6904 }));
List<double> maxList = myList.Select(l => l.Max()).ToList();
List<double> minList = myList.Select(l => l.Min()).ToList();

Try the following:
class Program
{
static void Main(string[] args)
{
var l = new List<List<double>>() {new List<Double>() {0, 16.0000, 15.0000, 0, 2.7217, 3.7217},
new List<Double>() {0, 0, 15.0000, 15.0000, 5.6904, 5.6904}};
int i = 1;
var result = from sublist in l
select new { min = sublist.Min(), max = sublist.Max(), index = i++ };
foreach (var r in result)
Console.WriteLine(String.Format("Index: {0} Min: {1} Max: {2}",r.index, r.min, r.max));
Console.ReadKey();
}
}
It will get the min- and max-value for each sub-list in the list of lists.

I assume obstVertex is declared like this:
List<List<double>> obstVertex;
Then you can do this
var minima = Enumerable.Range(0, obstVertex[0].Count - 1)
.Select (colIndex => obstVertex.Select(row => row[colIndex]).Min())
to get all the minimum values of each column.

static void Main(string[] args)
{
List<List<double>> lists = new List<List<double>>() {
new List<double>(){0 , 0 } ,
new List<double>(){16.0000 , 0 } ,
new List<double>(){16.0000 , 15.0000 } ,
new List<double>(){0 , 15.0000 } ,
new List<double>(){2.7217 , 5.6904 } ,
new List<double>(){3.7217 , 5.6904 }
};
var r = new {
col1_max = (from x in lists select x[0]).Max(),
col1_min = (from x in lists select x[0]).Min(),
col2_max = (from x in lists select x[1]).Max(),
col2_min = (from x in lists select x[1]).Min(),
};
Console.WriteLine(string.Format("col1_max = {0}\r\ncol1_min = {1}\r\ncol2_max = {2}\r\ncol3_max = {3}", r.col1_max , r.col1_min , r.col2_max , r.col2_min));
Console.Read();
}

Related

Dynamic number of nested for loops to list unique combinations of objects

I have n number of lists of objects which I need to convert to a list of object arrays each containing a unique combination of objects from the original lists.
Example:
myList[0] = new List<object>(){a, b, c, d};
myList[1] = new List<object>(){"0", "1", "2", "3", "4"};
myList[2] = new List<object>(){0, 1, 2};
myList[3] = new List<object>(){aClass, bClass}
etc.
Needs to become:
newList[0] = new object[]{a, "0", 0, aClass};
newList[1] = new object[]{a, "0", 0, bClass};
newList[2] = new object[]{a, "0", 1, aClass};
newList[3] = new object[]{a, "0", 1, bClass};
newList[4] = new object[]{a, "0", 2, aClass};
newList[5] = new object[]{a, "0", 2, bClass};
newList[6] = new object[]{a, "1", 0, aClass};
newList[7] = new object[]{a, "1", 0, bClass};
newList[8] = new object[]{a, "1", 1, aClass};
newList[9] = new object[]{a, "1", 1, bClass};
newList[10] = new object[]{a, "1", 2, aClass};
newList[11] = new object[]{a, "1", 2, bClass};
etc.
The order of the variables has to be preserved (the list at myList[0] has to be first, etc) because these object arrays are the parameters passed via reflection:
Indicator temp = (Indicator) newIndicator.Invoke(this, newList[i]);
If the number of lists of objects were static, it might look something like the following:
List<object[]> newList = new List<object[]>();
for(int i = 0; i < myList[0].Count; i++)
{
for(int i2 = 0; i2 < myList[1].Count; i2++)
{
for(int i3 = 0; i3 < myList[2].Count; i3++)
{
for(int i4 = 0; i4 < myList[3].Count; i4++)
{
object[] temp = new object[]{myList[0][i], myList[1][i2], myList[2][i3], myList[3][i4]};
newList.Add(temp);
}
}
}
}
My latest attempt was to create a list of indicies which held the current index of each list and incremented it appropriately, but my math doesn't seem to work out as I scale it out.
private List<object[]> ToParametersList(List<List<object>> listOfLists)
{
int counter = 1;
foreach(List<object> list in listOfLists){ counter *= list.Count; }
List<object[]> returnList = new List<object[]>();
List<int> indicies = new List<int>();
int tempSplit = 0;
List<int> splits = new List<int>();
List<int> splitcounters = new List<int>();
for(int i = 0; i < listOfLists.Count; i++)
{
if(i == 0 && listOfLists[0].Count > 2)
{
splits.Add(counter / listOfLists[0].Count);
tempSplit = counter / listOfLists[0].Count;
} else if(i > 0 && listOfLists[i].Count > 2) {
splits.Add(tempSplit / listOfLists[i].Count);
tempSplit /= listOfLists[i].Count;
} else if(listOfLists[i].Count == 2)
{
splits.Add(1);
}
indicies.Add(0);
splitcounters.Add(1);
}
for(int i = 0; i < counter; i++)
{
object[] newObject = new object[listOfLists.Count];
for(int i2 = 0; i2 < listOfLists.Count; i2++)
{
if(i < splits[i2] * splitcounters[i2] && ((indicies[i2] < listOfLists[i2].Count && listOfLists[i2].Count > 2) || indicies[i2] < listOfLists[i2].Count - 1))
{
newObject[i2] = listOfLists[i2][indicies[i2]];
}
else if(i >= splits[i2] * splitcounters[i2] && ((indicies[i2] < listOfLists[i2].Count && listOfLists[i2].Count > 2) || indicies[i2] < listOfLists[i2].Count - 1))
{
indicies[i2]++;
splitcounters[i2]++;
newObject[i2] = listOfLists[i2][indicies[i2]];
}
else
{
indicies[i2] = 0;
splitcounters[i2]++;
newObject[i2] = listOfLists[i2][indicies[i2]];
}
}
returnList.Add(newObject);
}
return returnList;
}
I have also gone through many of the recursion questions on here and am still having trouble understanding how to apply them to this particular situation (I am relatively new to recursion).
Any help would be greatly appreciated!
EDIT: In Cartesian products with n number of list the OP's post is confusing and the answer provided has no explanation of what is happening. The link to Eric Lippert's Blog is a general overview of Cartesian products which did not help me break the barrier that I needed to properly understand this in the context of what I was trying to do.
To be honest i did not read your last attempt. Other ways using Linq is great but if you really want a recursion follow this way.
To create a good recursion you need to look at which part of method varies and which part does not. the method should take parameters that varies for each call. Also you need if-else to end recursion somewhere.
List<object[]> newList = new List<object[]>();
for(int i = 0; i < myList[0].Count; i++)
{
for(int i2 = 0; i2 < myList[1].Count; i2++)
{
for(int i3 = 0; i3 < myList[2].Count; i3++)
{
for(int i4 = 0; i4 < myList[3].Count; i4++)
{
object[] temp = new object[]{myList[0][i], myList[1][i2], myList[2][i3], myList[3][i4]};
newList.Add(temp);
}
}
}
}
We want to use recursion in this method to be able to use it for any lenght of list.To do this you must convert loop into recursion call. but now you have unknown amount of loops.
The solution is to use params keyword. you can send any amount of int to method. this int's holds the variables i1, i2 , i3 , i4 .... just like the above method you have wrote.
The length of this array (params int[]) is exactly number of loops inside the normal method.
private static void Combine(List<List<object>> myList,List<object[]> newList,params int[] loopInd)
{
if (loopInd.Length <= myList.Count) // should not exceed number of loops.
{
int currentCount = myList[loopInd.Length - 1].Count;
while (loopInd[loopInd.Length - 1] < currentCount) // i<myList[0] , i2<myList[1] , i3<myList[2]
{
Combine(myList, newList, loopInd.Concat(new[] {0}).ToArray()); // Go for inner loop
loopInd[loopInd.Length - 1]++; // i++, i2++ , i3++ ...
}
}
else // no more loops.add the object[] into newList
{
int j = 0;
object[] temp = loopInd.Take(loopInd.Length - 1).Select(i => myList[j++][i]).ToArray();
newList.Add(temp);
}
}
The comments above shows the representations in normal method.
Then you can use it in this way.
List<List<object>> myList = new List<List<object>>();
myList.Add(new List<object>() { a, b, c, d });
myList.Add(new List<object>() { "0", "1", "2", "3", "4" });
myList.Add(new List<object>() { 0, 1, 2 });
myList.Add(new List<object>() {aClass, bClass});
List<object[]> newList = new List<object[]>();
Combine(myList, newList, 0);
// The newList is now what you want
Edit :
If you are after performance you can convert this Linq part
int j = 0;
object[] temp = loopInd.Take(loopInd.Length - 1).Select(i => myList[j++][i]).ToArray();
newList.Add(temp);
Into code
int j = 0;
object[] temp = new object[loopInd.Length - 1];
for (int i = 0; i < loopInd.Length - 1; i++,j++)
{
temp[i] = myList[j][loopInd[i]];
}
Here is a solution that accepts a number of lists that is unknown at compile time.
Method CombineArrayOfLists does what you need:
static List<List<object>> CombineArrayOfLists(List<object>[] myList)
{
List<List<object>> result = myList[0].Select(element => new List<object>() { element }).ToList();
for (int i = 1; i < myList.Length; i++)
{
result = (from c1 in result from c2 in myList[i] select new List<object>(c1) {c2}).ToList();
}
return result;
}
Note that you need to define the desired behavior in case any list in your array of lists is empty. To handle that case you may need to add an if statement to skip that list (if that is the appropriate thing to do).
A complete example written in a slightly more verbose form that could be easier to understand:
class Program
{
static void Main(string[] args)
{
List<object>[] myList = new List<object>[4];
AClass aClass = new AClass();
BClass bClass = new BClass();
myList[0] = new List<object>() { "a", "b", "c", "d" };
myList[1] = new List<object>() { "0", "1", "2", "3", "4" };
myList[2] = new List<object>() { 0, 1, 2 };
myList[3] = new List<object>() { aClass, bClass };
List<List<object>> result = CombineArrayOfLists(myList);
PrintList(result);
}
static List<List<object>> CombineArrayOfLists(List<object>[] myList)
{
List<List<object>> result = myList[0].Select(element => new List<object>() { element }).ToList();
for (int i = 1; i < myList.Length; i++)
{
result = CombineCollections(result, myList[i]).ToList();
}
return result;
}
private static IEnumerable<List<object>> CombineCollections(IEnumerable<List<object>> collection1, List<object> collection2)
{
return from c1 in collection1 from c2 in collection2 select new List<object>(c1) { c2 };
}
// A more verbose form of CombineCollections that may be easier to understand:
//private static IEnumerable<List<object>> CombineCollections(IEnumerable<List<object>> collection1, List<object> collection2)
//{
// foreach (List<object> c1 in collection1)
// {
// foreach (object c2 in collection2)
// {
// List<object> l1 = new List<object>(c1) { c2 };
// yield return l1;
// }
// }
//}
private static void PrintList(List<List<object>> collection)
{
collection.ForEach(list =>
{
list.ForEach(element =>
{
Console.Write(element);
Console.Write(" ");
});
Console.WriteLine();
});
}
}
public class AClass
{ }
public class BClass
{ }
You can use LINQ to get Cartesian product of list of objects.
List<object> arr1 = new List<object> { "a", "b", "c" };
List<object> arr2 = new List<object> { 3, 2, 4,5 };
List<object> arr3 = new List<object> { "0", "1", "2", "3", "4" };
var result = from x in arr1
from y in arr2
from z in arr3
select new { x = x, y = y,z=z };
List<object[]> newList = new List<object[]>();
foreach (var line in result)
{
newList.Add(new object[] { line.x, line.y, line.z });
}
foreach (var obj in newList)
{
foreach (var ele in obj)
{
Console.Write(ele.ToString() + " ");
}
Console.WriteLine();
}
Console.ReadKey();
This will provide you with the list of one objects in the way you require.
Here is the running example
http://csharppad.com/gist/45ebe7c9576dab9c00b8

Find a series of the same number in a List

I have a List of items containing either 1 or 0, I'm looking to output the items only where there are six 1's back to back in the list. So only write to the console if the item in this list is part of a group of six.
1
1
1
1
1
1
0
1
1
1
0
In the above list, the first six items would be output but the bottom set of three 1s would not as they are not part of a group of six.
Is this a job for LINQ or RegEx?
You can concatenate all values into string, then split it by zeros. From substrings select those which have at least 6 characters:
List<int> values = new List<int> { 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0 };
var series = String.Concat(values)
.Split(new[] { '0' }, StringSplitOptions.RemoveEmptyEntries)
.Where(s => s.Length >= 6);
For given input data series will contain single item "111111" which you can output to console.
Classic run length encoding, O(n), lazy evaluated, stack agnostic, generic for any equatable type.
public void TestRunLength()
{
var runs = new List<int>{ 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4, 4, 0, 4};
var finalGroup = RunLength(runs).FirstOrDefault(i => i.Count == 6 && i.First() == 1);
}
private IEnumerable<List<T>> RunLength<T>(IEnumerable<T> source) where T : IEquatable<T>
{
T current = default(T);
var requiresInit = true;
var list = new List<T>();
foreach (var i in source)
{
if (requiresInit)
{
current = i;
requiresInit = false;
}
if (i.Equals(current))
{
list.Add(i);
}
else
{
yield return list;
list = new List<T>{ i };
current = i;
}
}
if (list.Any())
{
yield return list;
}
}
And because it's lazy it works on infinite sequences (yes I know its not infinite, but it is large)!
public void TestRunLength()
{
var random = new Random();
var runs = Enumerable.Range(int.MinValue, int.MaxValue)
.Select(i => random.Next(0, 10));
var finalGroup = RunLength(runs)
.FirstOrDefault(i => i.Count == 6);
}
Probably it can be done with Regex too if you concatenate your numbers into a string. But I would prefer linq:
var bits = new List<int> {1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0};
int bitCountPerGroup = 6;
var result = bits // (1) (2)
.Select((x,idx) => bits.Skip(idx).TakeWhile(y => y == x))
.Where(g => g.Count() == bitCountPerGroup); // (3)
foreach (var set in result)
Console.WriteLine(string.Join(" ", set));
This code gets a number-set for each number by starting from the number (1) and taking the next numbers as long as they are equal (2). Then filter the groups and gets only those groups which have 6 numbers (3).
If for example your list is of an unknown size,or better,you do not know the items in it you could do this recursive example(note that i placed more zeros so it would fetch 2 sets of data,it works with yours also),and pass to the method the amout to group by:
//this is the datastructure to hold the results
static List<KeyValuePair<string, List<int>>> Set = new List<KeyValuePair<string, List<int>>>();
private static void GetData(List<int> lst, int group)
{
int count = 1;
int pivot = lst.First();
if (lst.Count < group)
{
return;
}
else
{
foreach (int i in lst.Skip(1))
{
if (i == pivot)
{
count++;
}
else if (count == group)
{
Set.Add(new KeyValuePair<string, List<int>>("Set of items " + pivot, lst.Take(count).ToList()));
GetData(lst.Skip(count).ToList(), group);
break;
}
else
{
GetData(lst.Skip(count).ToList(), group);
break;
}
}
}
}
Then in Main():
static void Main(string[] args)
{
List<int> test = new List<int> { 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0 };
GetData(test, 6);
foreach (var item in Set)
{
Console.WriteLine("\t" + item.Key);
foreach (var subitem in item.Value)
{
Console.WriteLine(subitem);
}
}
}

How can I get the sum (average) value of three lists in C#?

I have three lists which each list represents only 0s and 1s which related to the pixel values of three images.
My question is how can I get the sum (average) of those three lists and represent it in a new list?
here is example of my image1:
List<int> image1 = new List<int>();
int blackColor = 0;
for (int x = 0; x < bmp1.Width; x++)
{
for (int y = 0; y < bmp1.Height; y++)
{
Color color = bmp1.GetPixel(x, y);
if (color.ToArgb() == Color.Black.ToArgb())
{
image1.Add(0);
blackColor++;
}
else
{
image1.Add(1);
}
}
}
Let me makes sure I understand the problem. You have three lists of the same length:
list A: 1, 2, 4, 3
list B: 3, 2, 4, 1
List C: 2, 7, 1, 8
and you wish to get a third list that is the average of each:
List D: 2, 4, 3, 4
Yes?
This is a job for zip join.
var sumOfFirstTwo = list1.Zip(list2, (x, y)=>x + y);
sumOfFirstTwo is now the sequence that is the sum of the first two lists.
var sumOfAllThree = sumOfFirstTwo.Zip(list3, (x, y)=>x + y);
sumOfAllThree is now the sequence that is the sum of all three lists.
var average = sumOfAllThree.Select(x=>x/3).ToList();
Make sense?
This works for an arbitrary number of lists
var firstList = new[] { 1, 2, 3, 1 };
var secondList = new[] { 2, 3, 1, 1 };
var thirdList = new[] { 3, 1, 2, 2 };
var lists = new[] { firstList, secondList, thirdList };
var listLengths = lists.Select(x => x.Count());
if (listLengths.Distinct().Count() != 1)
throw new Exception("Line lengths must be the same");
var lengthOfEachList = listLengths.First();
var averages = new List<double>();
for (var i = 0; i != lengthOfEachList; ++i) {
averages.Add(lists.Average(x => x[i]));
}
The LINQ way would be
var averages = Enumerable.Range(0, lengthOfEachList).Select(x => lists.Average(y => y[x]));

how to add array elements in one array according to condition in other array in C#?

I have two arrays say one is string array and the other is int array
string array has---> "11","11","11","11","12","12" elements and the int array has 1,2,3,4,5,6 respectively.
I want result two arrays containing string array--->"11","12"
and int array---->10,11
If the string array has duplicate elements, the other array containing that respective index value must be added .For example "11" is in 1st,2nd,3rd,4th index So its corresponding value must sum of all those elements in other array.Can it be done?
I have written some code but unable to do it..
static void Main(string[] args)
{
//var newchartValues = ["","","","","","",""];
//var newdates = dates.Split(',');
//string[] newchartarray = newchartValues;
//string[] newdatearray = newdates;
int[] newchartValues = new int[] { 1, 2, 3, 4, 5, 6 };
string[] newdates = new string[] { "11", "11","11","12","12","12" };
int[] intarray = new int[newchartValues.Length];
List<int> resultsumarray = new List<int>();
for (int i = 0; i < newchartValues.Length - 1; i++)
{
intarray[i] = Convert.ToInt32(newchartValues[i]);
}
for (int i = 0; i < newdates.Length; i++)
{
for (int j = 0; j < intarray.Length; j++)
{
if (newdates[i] == newdates[i + 1])
{
intarray[j] += intarray[j + 1];
resultsumarray.Add(intarray[j]);
}
}
resultsumarray.ToArray();
}
}
I don't quite get what you need, but I think I fixed your code, result will contain 10 and 11 in this example:
int[] newchartValues = new int[] { 1, 2, 3, 4, 5, 6 };
string[] newdates = new string[] { "11", "11", "11", "11", "12", "12" };
List<int> result = new List<int>();
if (newdates.Length == 0)
return;
string last = newdates[0];
int cursum = newchartValues[0];
for (var i = 1; i <= newdates.Length; i++)
{
if (i == newdates.Length || newdates[i] != last)
{
result.Add(cursum);
if (i == newdates.Length)
break;
last = newdates[i];
cursum = 0;
}
cursum += newchartValues[i];
}
Here is an approach that should do what you want:
List<int> resultsumarray = newdates
.Select((str, index) => new{ str, index })
.GroupBy(x => x.str)
.Select(xg => xg.Sum(x => newchartValues[x.index]))
.ToList();
Result is a List<int> with two number: 6, 15
Something like this?
int[] newchartValues = new int[] { 1, 2, 3, 4, 5, 6 };
int[] newdates = new int[] { 11, 11,11,12,12,12 };
var pairs = Enumerable.Zip(newdates, newchartValues, (x, y) => new { x, y })
.GroupBy(z => z.x)
.Select(g => new { k = g.Key, s = g.Sum(z => z.y) })
.ToList();
var distinctDates = pairs.Select(p => p.k).ToArray();
var sums = pairs.Select(p => p.s).ToArray();

get common elements in lists in C#

I have two sorted lists as below:
var list1 = new List<int>() { 1, 1, 1, 2, 3 };
var list2 = new List<int>() { 1, 1, 2, 2, 4 };
I want the output to be: {1, 1, 2}
How to do this in C#?
Is there a way using Linq?
Use Intersect:
var commonElements = list1.Intersect(list2).ToList();
The extra 1 means you can't use Intersect because it returns a set.
Here's some code that does what you need:
var list1 = new List<int>() { 1, 1, 1, 2, 3 };
var list2 = new List<int>() { 1, 1, 2, 2, 4 };
var grouped1 =
from n in list1
group n by n
into g
select new {g.Key, Count = g.Count()};
var grouped2 =
from n in list2
group n by n
into g
select new {g.Key, Count = g.Count()};
var joined =
from b in grouped2
join a in grouped1 on b.Key equals a.Key
select new {b.Key, Count = Math.Min(b.Count, a.Count)};
var result = joined.SelectMany(a => Enumerable.Repeat(a.Key, a.Count));
CollectionAssert.AreEquivalent(new[] {1, 1, 2}, result);
This works nicely:
var list1 = new List<int>() { 1, 1, 1, 2, 3 };
var list2 = new List<int>() { 1, 1, 2, 2, 4 };
var lookup1 = list1.ToLookup(x => x);
var lookup2 = list2.ToLookup(x => x);
var results = lookup1.SelectMany(l1s => lookup2[l1s.Key].Zip(l1s, (l2, l1) => l1));
While both #Austin Salonen's solution and #Enigmativity's solution work for any given lists, neither take advantage of OP's condition that the lists are sorted.
Given that both lists will be ordered we can do a search in O(n + m) time where n and m are the length of each list. Not entirely sure what the previous solutions big o performance is, but it's definitely slower then O(n + m).
Basically we just walk both lists, moving one or both enumerators based on a comparison check.
var results = new List<int>();
var e1 = list1.GetEnumerator();
var e2 = list2.GetEnumerator();
var hasNext = e1.MoveNext() && e2.MoveNext();
while (hasNext) {
var value1 = e1.Current;
var value2 = e2.Current;
if (value1 == value2) {
results.Add(value1);
hasNext = e1.MoveNext() && e2.MoveNext();
} else if (value1 < value2) {
hasNext = e1.MoveNext();
} else if (value1 > value2) {
hasNext = e2.MoveNext();
}
}
That's it! results will be an empty list if no matches are found.
Note this assumes both lists are in ascending order. If it's descending, just flip the < and > operators.
I am late in answering this question, this might help future visitors.
List<int> p = new List<int> { 1, 1, 1, 2, 3 };
List<int> q = new List<int> { 1, 1, 2, 2, 4 };
List<int> x = new List<int>();
for (int i = 0; i < p.Count; i++ )
{
if (p[i] == q[i])
{
x.Add(p[i]);
}
}

Categories

Resources