LINQ swap columns into rows - c#

Is there a fancy LINQ expression that could allow me to do the following in a much more simpler fashion. I have a List<List<double>>, assuming the List are columns in a 2d matrix, I want to swap the list of columns into a list of rows. I have the following obvious solution:
int columns = 5;
var values; // assume initialised as List<List<double>>()
var listOfRows = new List<List<double>>();
for (int i = 0; i < columns ; i++)
{
List<double> newRow = new List<double>();
foreach (List<double> value in values)
{
newRow.Add(value[i]);
}
listOfRows.Add(newRow);
}

You could LINQify the inner loop pretty easily:
vector.AddRange(values.Select(value => value[i]));
Whether or not that improves the readability is left entirely up to you!

Here's a Linq expression that would do what you want - looking at it I'd personally stick with the nested foreach loops though - much easier to read:
var columnList= new List<List<double>>();
columnList.Add(new List<double>() { 1, 2, 3 });
columnList.Add(new List<double>() { 4, 5, 6 });
columnList.Add(new List<double>() { 7, 8, 9 });
columnList.Add(new List<double>() { 10, 11, 12 });
int columnCount = columnList[0].Count;
var rowList = columnList.SelectMany(x => x)
.Select((x, i) => new { V = x, Index = i })
.GroupBy(x => (x.Index + 1) % columnCount)
.Select(g => g.Select( x=> x.V).ToList())
.ToList();
This example also would only work on a matrix with a fixed column count. Basically it's flattening the matrix into a list, then creating the list of rows by grouping by the index of the element in the list modulo the column count.
Edit:
A different approach, much closer to a nested loop and probably similar performance besides the overhead.
int columnCount = columnList[0].Count;
int rowCount = columnList.Count;
var rowList = Enumerable.Range(0, columnCount)
.Select( x => Enumerable.Range(0, rowCount)
.Select(y => columnList[y][x])
.ToList())
.ToList();

var inverted = Enumerable.Range(0, columnCount)
.Select(index => columnList.Select(list => list[index]));
In short, we enumerate the column index from a range and use it to collect the nth element of each list.
Please note that you'll need to check that every list has the same number of columns.

Here's one that works for rectangular (non-ragged) matrices. The C# code here works cut-and-paste into LinqPad, a free, interactive C# programming tool.
I define a postfix operator (that is, an extension method) "Transpose." Use the operator as follows:
var rand = new Random();
var xss = new [] {
new [] {rand.NextDouble(), rand.NextDouble()},
new [] {rand.NextDouble(), rand.NextDouble()},
new [] {rand.NextDouble(), rand.NextDouble()},
};
xss.Dump("Original");
xss.Transpose().Dump("Transpose");
resulting in something like this:
Original
0.843094345109116
0.981432441613373
0.649207864724662
0.00594645645746331
0.378864820291691
0.336915332515219
Transpose
0.843094345109116
0.649207864724662
0.378864820291691
0.981432441613373
0.00594645645746331
0.336915332515219
The gist of the implementation of this operator is the following
public static IEnumerable<IEnumerable<T>> Transpose<T>(this IEnumerable<IEnumerable<T>> xss)
{
var heads = xss.Heads();
var tails = xss.Tails();
var empt = new List<IEnumerable<T>>();
if (heads.IsEmpty())
return empt;
empt.Add(heads);
return empt.Concat(tails.Transpose());
}
Here is the full implementation, with some lines commented out that you can uncomment to monitor how the function works.
void Main()
{
var rand = new Random();
var xss = new [] {
new [] {rand.NextDouble(), rand.NextDouble()},
new [] {rand.NextDouble(), rand.NextDouble()},
new [] {rand.NextDouble(), rand.NextDouble()},
};
xss.Dump("Original");
xss.Transpose().Dump("Transpose");
}
public static class Extensions
{
public static IEnumerable<T> Heads<T>(this IEnumerable<IEnumerable<T>> xss)
{
Debug.Assert(xss != null);
if (xss.Any(xs => xs.IsEmpty()))
return new List<T>();
return xss.Select(xs => xs.First());
}
public static bool IsEmpty<T>(this IEnumerable<T> xs)
{
return xs.Count() == 0;
}
public static IEnumerable<IEnumerable<T>> Tails<T>(this IEnumerable<IEnumerable<T>> xss)
{
return xss.Select(xs => xs.Skip(1));
}
public static IEnumerable<IEnumerable<T>> Transpose<T>(this IEnumerable<IEnumerable<T>> xss)
{
// xss.Dump("xss in Transpose");
var heads = xss.Heads()
// .Dump("heads in Transpose")
;
var tails = xss.Tails()
// .Dump("tails in Transpose")
;
var empt = new List<IEnumerable<T>>();
if (heads.IsEmpty())
return empt;
empt.Add(heads);
return empt.Concat(tails.Transpose())
// .Dump("empt")
;
}
}

I am combining some of the answers above, which sometimes had columns and rows inverted form the original answer or from the convention I am used to : row refers to the first index and column to the inner ( second) index. e.g. values[row][column]
public static List<List<T>> Transpose<T>(this List<List<T>> values)
{
if (values.Count == 0 || values[0].Count == 0)
{
return new List<List<T>>();
}
int ColumnCount = values[0].Count;
var listByColumns = new List<List<T>>();
foreach (int columnIndex in Enumerable.Range(0, ColumnCount))
{
List<T> valuesByColumn = values.Select(value => value[columnIndex]).ToList();
listByColumns.Add(valuesByColumn);
}
return listByColumns;
}
Actually the word row and column is just our convention of thinking about the data in rows and columns , and sometimes adds more confusion than solving them.
We are actually just swapping the inner index for the outer index. (or flipping the indexes around). So one could also just define the following extension method. . Again I borrowed from above solutions, just put it into something I find readable and fairly compact.
Checks that the inner lists are of equal sized are required.
public static List<List<T>> InsideOutFlip<T>(this List<List<T>> values)
{
if (values.Count == 0 || values[0].Count == 0)
{
return new List<List<T>>();
}
int innerCount = values[0].Count;
var flippedList = new List<List<T>>();
foreach (int innerIndex in Enumerable.Range(0, innerCount))
{
List<T> valuesByOneInner = values.Select(value => value[innerIndex]).ToList();
flippedList.Add(valuesByOneInner);
}
return flippedList;
}

Related

Merge first list with second list based on standard deviation of second list C#

Given 2 datasets (which are both a sequence of standard deviations away from a number, we are looking for the overlapping sections):
var list1 = new decimal[] { 357.06, 366.88, 376.70, 386.52, 406.15 };
var list2 = new decimal[] { 370.51, 375.62, 380.72, 385.82, 390.93 };
I would like to perform a merge with items from List2 being placed closest to items of List1, within a certain range, i.e. merge List2 element within 5.10 (standard deviation) of List1 element:
357.06
366.88 => 370.51
376.70 => 375.52, 380.72
386.52 => 390.93
406.15
The idea is to cluster values from List2 and count them, in this case element with value 376.70 would have the highest significance as it has 2 close neighbors of 375.52 and 380.72 (where as 366.88 and 386.52 have only 1 match, and the remaining none within range).
Which C# math/stats libraries could be used for this (or would there be a better way to combine statistically)?
If this is more of a computer science or stats question apologies in advance will close and reopen on relevant SO site.
Assuming that list2 is sorted (if not, put Array.Sort(list2);) you can try Binary Search:
Given:
var list1 = new decimal[] { 357.06m, 366.88m, 376.70m, 386.52m, 406.15m };
var list2 = new decimal[] { 370.51m, 375.62m, 380.72m, 385.82m, 390.93m };
decimal sd = 5.10m;
Code:
// Array.Sort(list2); // Uncomment, if list2 is not sorted
List<(decimal value, decimal[] list)> result = new List<(decimal value, decimal[] list)>();
foreach (decimal value in list1) {
int leftIndex = Array.BinarySearch<decimal>(list2, value - sd);
if (leftIndex < 0)
leftIndex = -leftIndex - 1;
else // edge case
for (; leftIndex >= 1 && list1[leftIndex - 1] == value - sd; --leftIndex) ;
int rightIndex = Array.BinarySearch<decimal>(list2, value + sd);
if (rightIndex < 0)
rightIndex = -rightIndex - 1;
else // edge case
for (; rightIndex < list1.Length - 1 && list1[rightIndex + 1] == value + sd; ++rightIndex) ;
result.Add((value, list2.Skip(leftIndex).Take(rightIndex - leftIndex).ToArray()));
}
Let's have a look:
string report = string.Join(Environment.NewLine, result
.Select(item => $"{item.value} => [{string.Join(", ", item.list)}]"));
Console.Write(report);
Outcome:
357.06 => []
366.88 => [370.51]
376.70 => [375.62, 380.72]
386.52 => [385.82, 390.93]
406.15 => []
Something like this should work
var list1 = new double[] { 357.06, 366.88, 376.70, 386.52, 406.15 };
var list2 = new double[] { 370.51, 375.62, 380.72, 385.82, 390.93 };
double dev = 5.1;
var result = new Dictionary<double, List<double>>();
foreach (var l in list2) {
var diffs = list1.Select(r => new { diff = Math.Abs(r - l), r })
.Where(d => d.diff <= dev)
.MinBy(r => r.diff)
.FirstOrDefault();
if (diffs == null) {
continue;
}
List<double> list;
if (! result.TryGetValue(diffs.r, out list)) {
list = new List<double>();
result.Add(diffs.r, list);
}
list.Add(l);
}
It uses MinBy from MoreLinq, but it is easy to modify to work without it.
In fact, you don't need extra libs or something else. You can use just LINQ for this.
internal class Program
{
private static void Main(string[] args)
{
var deviation = 5.1M;
var list1 = new decimal[] { 357.06M, 366.88M, 376.70M, 386.52M, 406.15M };
var list2 = new decimal[] { 370.51M, 375.62M, 380.72M, 385.82M, 390.93M };
var result = GetDistribution(list1.ToList(), list2.ToList(), deviation);
result.ForEach(x => Console.WriteLine($"{x.BaseValue} => {string.Join(", ", x.Destribution)} [{x.Weight}]"));
Console.ReadLine();
}
private static List<Distribution> GetDistribution(List<decimal> baseList, List<decimal> distrebutedList, decimal deviation)
{
return baseList.Select(x =>
new Distribution
{
BaseValue = x,
Destribution = distrebutedList.Where(y => x - deviation < y && y < x + deviation).ToList()
}).ToList();
}
}
internal class Distribution
{
public decimal BaseValue { get; set; }
public List<decimal> Destribution { get; set; }
public int Weight => Destribution.Count;
}
I hope it was useful for you.

How to find modal value accross List<List<double>> for each inner value?

This is remarkably similar to another question I asked previously. I have no idea how to do things in Linq so I need some help with this one. I want to find the Modal value of a List> for each inner value.
I have the following list:
List<List<double>> myFullList = new List<List<double>>();
for(int i = 1; i <= numberOfLoops; i++)
{
List<double> myInnerList = new List<double>();
for(int i = 1; i <= 10; i++)
{
// Populate inner list with random numbers
myInnerList.Add(double myRandomNumber);
}
// Add the inner list to the full list
myFullList.Add(myInnerList);
}
The list should look something like this:
myFullList[0] = {rand#1,rand#2,rand#3,...,rand#10}
myFulllist[1] = {rand#1,rand#2,rand#3,...,rand#10}
.
.
.
.
myFulllist[1] = {rand#1,rand#2,rand#3,...,rand#10}
I need to find the MODAL VALUE for that data to form ONE single list that looks something like this:
List<double> mode= new List<double>();
mode= {mode#1, mode#2........mode#10}
This output variable will find the mode of the data for the same "row" of data in the inner list.
Simple example:
innerList[0] = {1.00,2.00,3.00};
innerList[1] = {3.00,2.00,8.00};
innerList[2] = {3.00,9.00,1.00};
innerList[3] = {3.00,1.00,1};
fullList = {innerList[0], innerList[1], innerList[2], innerList[3]};
modeList = {3,2,1};
Not the most elegant way, but probably easier to Understand. It has been succesfully tested :)
class Program
{
static void Main(string[] args)
{
Random rnd = new Random();
int numberOfLoops = 10;
List<List<int>> myFullList = new List<List<int>>();
for (int i = 0; i < numberOfLoops; i++)
{
List<int> myInnerList = new List<int>();
for (int j = 0; j < 10; j++)
{
// Populate inner list with random numbers
myInnerList.Add(rnd.Next(0, 10));
}
// Add the inner list to the full list
myFullList.Add(myInnerList);
}
myFullList = Transpose<int>(myFullList);
List<int> result = new List<int>();
foreach (List<int> subList in myFullList)
result.Add(Mode(subList));
//TO-DO: linq version!
//List<int> result = myFullList.ForEach(num => Mode(num));
}
public static int Mode(List<int> x)
{
int mode = x.GroupBy(v => v)
.OrderByDescending(g => g.Count())
.First()
.Key;
return mode;
}
public static List<List<T>> Transpose<T>(List<List<T>> lists)
{
var longest = lists.Any() ? lists.Max(l => l.Count) : 0;
List<List<T>> outer = new List<List<T>>(longest);
for (int i = 0; i < longest; i++)
outer.Add(new List<T>(lists.Count));
for (int j = 0; j < lists.Count; j++)
for (int i = 0; i < longest; i++)
outer[i].Add(lists[j].Count > i ? lists[j][i] : default(T));
return outer;
}
}
That's quiet simple, here is code (sorry, haven't fully tested it, but it's good to start with):
public static class ModalHelper
{
public static List<double> GetModals(List<List<double>> source)
{
return source.Select(list => list.Sum()/list.Count).ToList();
}
}
This linq query should do the trick
var result = list.Select<List<double>, List<KeyValuePair<int, double>>>(sub =>
{
List<KeyValuePair<int, double>> elems = new List<KeyValuePair<int, double>>(sub.Count);
for (int i = 0; i < sub.Count; ++i)
elems.Add(new KeyValuePair<int, double>(i, sub[i]));
return elems;
}).SelectMany((x) => x).GroupBy((x) => x.Key).Select<IGrouping<int, KeyValuePair<int, double>>, double>(x =>
{
var y = x.GroupBy(g => g.Value).OrderByDescending(g => g.Count());
return y.First().First().Value;
});
Here is an example:
static void Main(string[] args)
{
List<List<double>> list = new List<List<double>>();
list.Add(new List<double> { 1.00, 2.00, 3.00 });
list.Add(new List<double> { 3.00, 2.00, 8.00 });
list.Add(new List<double> { 3.00, 9.00, 1.00 });
list.Add(new List<double> { 3.00, 1.00, 1 });
var result = list.Select<List<double>, List<KeyValuePair<int, double>>>(sub =>
{
List<KeyValuePair<int, double>> elems = new List<KeyValuePair<int, double>>(sub.Count);
for (int i = 0; i < sub.Count; ++i)
elems.Add(new KeyValuePair<int, double>(i, sub[i]));
return elems;
}).SelectMany((x) => x).GroupBy((x) => x.Key).Select<IGrouping<int, KeyValuePair<int, double>>, double>(x =>
{
var y = x.GroupBy(g => g.Value).OrderByDescending(g => g.Count());
return y.First().First().Value;
});
foreach (double val in result)
Console.Write(val + " ");
Console.WriteLine();
}
Here a live version at ideone: http://ideone.com/ye2EhG
First the lists are transformed to lists of key-value-pairs which add the information of the index inside each list. Then these lists are flattened to one single list and then this new list is grouped by the index. The groups are ordered by the count of values and the most-frequent element is returned for each group.
Something like this should give the mode:
var temp = myFullList.SelectMany(l => l).GroupBy(all => all).Select(result => new
{
Value = result.Key,
Count = result.Count()
}).OrderByDescending(t => t.Count);
Explanation:
From MSDN - The SelectMany
Projects each element of a sequence to an IEnumerable and flattens
the resulting sequences into one sequence.
So it gives us each decimal from the sub lists. We then group that by the decimals themselves and select the count for each along with their value. Finally we order by the count to give the most frequently occurring decimals first.
Edit based on the comment from Robert S
It seems the above code isn't what was required. As Robert S points out that code gives the mode of ALL numbers in the List<List<double>> but the question is how to get the mode from each column.
The following code should give the mode per column. Note that this code ignores duplicates; if more than one number appears the same amount of times the first number will be given:
var result1 = myFullList[0].Select((l, i) => new
{
Column = i,
Mode = myFullList.GroupBy(fl => fl[i]).OrderByDescending(t => t.Count()).Select(t => t.Key).FirstOrDefault()
});
foreach (var item in result1)
{
Console.WriteLine(string.Format("{0} {1}", item.Column, item.Mode));
}
The code is using the overload of Select to take the index of the element (the column in the OP's definition). It then groups each item at that index. Note there are no bounds checks on myFullList but in production code there should be.
If duplicates are an issue we need two steps:
var temp2 = myFullList[0].Select((l, i) => new
{
Column = i,
Mode = myFullList.GroupBy(fl => fl[i]).Select(t => new { Number = t.Key, Count = t.Count() }).OrderByDescending(a => a.Count)
});
var result2 = temp2.Select(t => new
{
Column = t.Column,
Mode = t.Mode.Where(m => m.Count == t.Mode.Max(tm => tm.Count))
});
foreach (var item in result2)
{
for (int i = 0; i < item.Mode.Count(); i++)
{
Console.WriteLine(string.Format("{0} {1}", item.Column, item.Mode.ElementAt(i)));
}
}
In the above code temp2.Mode will contain an IEnumerable of an anonymous object containing the number and how many times that number has appeared. result2 is then populated by grabbing each of those items where the count matches the max of the count.
Given the input:
myFullList.Add(new List<double> { 1.00, 2.00, 3.00 });
myFullList.Add(new List<double> { 3.00, 2.00, 3.00 });
myFullList.Add(new List<double> { 3.00, 9.00, 1.00 });
myFullList.Add(new List<double> { 3.00, 1.00, 1 });
The first code outputs
0 3
1 2
2 3
and the second outputs
0 3
1 2
2 3
2 1
Note we have two outputs for column 2 as both 3 and 1 are equally popular.

Splitting an array using LINQ

I have a collection uni-dimensional like this:
[1,2,4,5.....n]
I would like to convert that collection in a bi-dimensional collection like this:
[[1,2,3],
[4,5,6],
...]
Basically I want to group or split if you want, the array in groups of 'n' members
I can do it with a foreach statement, but I am currently learning LINQ so instead of iterating through all elements and create a new array manually I would like to use the LINQ features (if applicable)
Is there any LINQ function to help me to accomplish this??
I was thinking in the GroupBy or SelectMany I do not know if they will help me though but they might
Any help will be truly appreciate it =) :**
You can group by the index divided by the batch size, like this:
var batchSize = 3;
var batched = orig
.Select((Value, Index) => new {Value, Index})
.GroupBy(p => p.Index/batchSize)
.Select(g => g.Select(p => p.Value).ToList());
Use MoreLinq.Batch
var result = inputArray.Batch(n); // n -> batch size
Example
var inputs = Enumerable.Range(1,10);
var output = inputs.Batch(3);
var outputAsArray = inputs.Batch(3).Select(x=>x.ToArray()).ToArray(); //If require as array
You want Take() and Skip(). These methods will let you split an IEnumerable. Then you can use Concat() to slap them together again.
The sample below will split an array into groups of 4 items each.
int[] items = Enumerable.Range(1, 20).ToArray(); // Generate a test array to split
int[][] groupedItems = items
.Select((item, index) => index % 4 == 0 ? items.Skip(index).Take(4).ToArray() : null)
.Where(group => group != null)
.ToArray();
It's not a pure LINQ but it's intended to be used with it:
public static class MyEnumerableExtensions
{
public static IEnumerable<T[]> Split<T>(this IEnumerable<T> source, int size)
{
if (source == null)
{
throw new ArgumentNullException("source can't be null.");
}
if (size == 0)
{
throw new ArgumentOutOfRangeException("Chunk size can't be 0.");
}
List<T> result = new List<T>(size);
foreach (T x in source)
{
result.Add(x);
if (result.Count == size)
{
yield return result.ToArray();
result = new List<T>(size);
}
}
}
}
It can be used from your code as:
private void Test()
{
// Here's your original sequence
IEnumerable<int> seq = new[] { 1, 2, 3, 4, 5, 6 };
// Here's the result of splitting into chunks of some length
// (here's the chunks length equals 3).
// You can manipulate with this sequence further,
// like filtering or joining e.t.c.
var splitted = seq.Split(3);
}
It's as simple as:
static class LinqExtensions
{
public static IEnumerable<IEnumerable<T>> ToPages<T>(this IEnumerable<T> elements, int pageSize)
{
if (elements == null)
throw new ArgumentNullException("elements");
if (pageSize <= 0)
throw new ArgumentOutOfRangeException("pageSize","Must be greater than 0!");
int i = 0;
var paged = elements.GroupBy(p => i++ / pageSize);
return paged;
}
}
I based my solution of Jeremy Holovacs's answer and used Take() and Skip() to create subarrays.
const int batchSize = 3;
int[] array = new int[] { 1,2,4,5.....n};
var subArrays = from index in Enumerable.Range(0, array.Length / batchSize + 1)
select array.Skip(index * batchSize).Take(batchSize);
Starting with .NET 6, there is the System.Linq.Enumerable.Chunk(this IEnumerable<TSource>, int size) extension method. It returns an IEnumerable<TSource[]> where each item is an array of size elements, except the last item, which could have fewer.
Code like this:
using System;
using System.Collections.Generic;
using System.Linq;
int[] input = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
IEnumerable<int[]> chunks = input.Chunk(3);
foreach (int[] chunk in chunks)
{
foreach (int i in chunk)
{
Console.Write($"{i} ");
}
Console.WriteLine();
}
outputs
1 2 3
4 5 6
7 8 9
10

Find indices of particular items in the list using linq

I have a list of integers from 1 to 20. I want the indices of items which are greater than 10 using linq. Is it possible to do with linq?
Thanks in advance
Use the overload of Select which includes the index:
var highIndexes = list.Select((value, index) => new { value, index })
.Where(z => z.value > 10)
.Select(z => z.index);
The steps in turn:
Project the sequence of values into a sequence of value/index pairs
Filter to only include pairs where the value is greater than 10
Project the result to a sequence of indexes
public static List<int> FindIndexAll(this List<int> src, Predicate<int> value)
{
List<int> res = new List<int>();
var idx = src.FindIndex(x=>x>10);
if (idx!=-1) {
res.Add(idx);
while (true)
{
idx = src.FindIndex(idx+1, x => x > 10);
if (idx == -1)
break;
res.Add(idx);
}
}
return res;
}
Usage
List<int> test= new List<int>() {1,10,5,2334,34,45,4,4,11};
var t = test.FindIndexAll(x => x > 10);

C#: Altering values for every item in an array

I'm wondering if there is built-in .NET functionality to change each value in an array based on the result of a provided delegate. For example, if I had an array {1,2,3} and a delegate that returns the square of each value, I would like to be able to run a method that takes the array and delegate, and returns {1,4,9}. Does anything like this exist already?
LINQ provides support for projections using the Select extension method:
var numbers = new[] {1, 2, 3};
var squares = numbers.Select(i => i*i).ToArray();
You can also use the slightly less fluent Array.ConvertAll method:
var squares = Array.ConvertAll(numbers, i => i*i);
Jagged arrays can be processed by nesting the projections:
var numbers = new[] {new[] {1, 2}, new[] {3, 4}};
var squares = numbers.Select(i => i.Select(j => j*j).ToArray()).ToArray();
Multidimensional arrays are a little more complex. I've written the following extension method which projects every element in a multidimensional array no matter what its rank.
static Array ConvertAll<TSource, TResult>(this Array source,
Converter<TSource, TResult> projection)
{
if (!typeof (TSource).IsAssignableFrom(source.GetType().GetElementType()))
{
throw new ArgumentException();
}
var dims = Enumerable.Range(0, source.Rank)
.Select(dim => new {lower = source.GetLowerBound(dim),
upper = source.GetUpperBound(dim)});
var result = Array.CreateInstance(typeof (TResult),
dims.Select(dim => 1 + dim.upper - dim.lower).ToArray(),
dims.Select(dim => dim.lower).ToArray());
var indices = dims
.Select(dim => Enumerable.Range(dim.lower, 1 + dim.upper - dim.lower))
.Aggregate(
(IEnumerable<IEnumerable<int>>) null,
(total, current) => total != null
? total.SelectMany(
item => current,
(existing, item) => existing.Concat(new[] {item}))
: current.Select(item => (IEnumerable<int>) new[] {item}))
.Select(index => index.ToArray());
foreach (var index in indices)
{
var value = (TSource) source.GetValue(index);
result.SetValue(projection(value), index);
}
return result;
}
The above method can be tested with an array of rank 3 as follows:
var source = new int[2,3,4];
for (var i = source.GetLowerBound(0); i <= source.GetUpperBound(0); i++)
for (var j = source.GetLowerBound(1); j <= source.GetUpperBound(1); j++)
for (var k = source.GetLowerBound(2); k <= source.GetUpperBound(2); k++)
source[i, j, k] = i*100 + j*10 + k;
var result = (int[,,]) source.ConvertAll<int, int>(i => i*i);
for (var i = source.GetLowerBound(0); i <= source.GetUpperBound(0); i++)
for (var j = source.GetLowerBound(1); j <= source.GetUpperBound(1); j++)
for (var k = source.GetLowerBound(2); k <= source.GetUpperBound(2); k++)
{
var value = source[i, j, k];
Debug.Assert(result[i, j, k] == value*value);
}
Not that I'm aware of (replacing each element rather than converting to a new array or sequence), but it's incredibly easy to write:
public static void ConvertInPlace<T>(this IList<T> source, Func<T, T> projection)
{
for (int i = 0; i < source.Count; i++)
{
source[i] = projection(source[i]);
}
}
Use:
int[] values = { 1, 2, 3 };
values.ConvertInPlace(x => x * x);
Of course if you don't really need to change the existing array, the other answers posted using Select would be more functional. Or the existing ConvertAll method from .NET 2:
int[] values = { 1, 2, 3 };
values = Array.ConvertAll(values, x => x * x);
This is all assuming a single-dimensional array. If you want to include rectangular arrays, it gets trickier, particularly if you want to avoid boxing.
Using System.Linq you could do something like:
var newArray = arr.Select(x => myMethod(x)).ToArray();
LINQ queries could easily solve this for you - make sure you're referencing System.Core.dll and have a
using System.Linq;
statement. For example, if you had your array in a variable named numberArray, the following code would give you exactly what you're looking for:
var squares = numberArray.Select(n => n * n).ToArray();
The final "ToArray" call is only needed if you actually need an array, and not an IEnumerable<int>.
you can use linq to accomplish this in shorthand but be careful remember that a foreach occurs underneath anyway.
int[] x = {1,2,3};
x = x.Select(( Y ) => { return Y * Y; }).ToArray();
Here is another solution for M x N arrays, where M and N are not known at compile time.
// credit: https://blogs.msdn.microsoft.com/ericlippert/2010/06/28/computing-a-cartesian-product-with-linq/
public static IEnumerable<IEnumerable<T>> CartesianProduct<T>(IEnumerable<IEnumerable<T>> sequences)
{
IEnumerable<IEnumerable<T>> result = new[] { Enumerable.Empty<T>() };
foreach (var sequence in sequences)
{
// got a warning about different compiler behavior
// accessing sequence in a closure
var s = sequence;
result = result.SelectMany(seq => s, (seq, item) => seq.Concat<T>(new[] { item }));
}
return result;
}
public static void ConvertInPlace(this Array array, Func<object, object> projection)
{
if (array == null)
{
return;
}
// build up the range for each dimension
var dimensions = Enumerable.Range(0, array.Rank).Select(r => Enumerable.Range(0, array.GetLength(r)));
// build up a list of all possible indices
var indexes = EnumerableHelper.CartesianProduct(dimensions).ToArray();
foreach (var index in indexes)
{
var currentIndex = index.ToArray();
array.SetValue(projection(array.GetValue(currentIndex)), currentIndex);
}
}

Categories