I have the following class
class Tile
{
public int height;
public int terrain;
}
And I have a 2D array of Tiles
Tile[,] area = new Tile[5,5];
How could I map my area from a Tile[,] to a int[,], where only the height is saved?
I tried doing this:
area.Select(tile => tile.height)
but apparently C# Multidimensional arrays do not implement IEnumerable.
How could I solve this problem?
How could I solve this problem?
By writing code. There's no "select" that works, so make your own:
static class Extensions
{
public static R[,] Select<T, R>(this T[,] items, Func<T, R> f)
{
int d0 = items.GetLength(0);
int d1 = items.GetLength(1);
R[,] result = new R[d0, d1];
for (int i0 = 0; i0 < d0; i0 += 1)
for (int i1 = 0; i1 < d1; i1 += 1)
result[i0, i1] = f(items[i0, i1]);
return result;
}
}
And now you have the extension method you want.
EXERCISES:
Which of the standard LINQ sequence operators make sense to adapt to multidimensional arrays, and which do not?
Are there operators you'd like to see on multidimensional arrays that are not standard LINQ operators but which you could implement as extension methods?
As there is no out of the box way to do this, you may try the workaround proposed here:
Extracted from the original post and all credit goes to original poster: Enumerating on Multi-dimentional arrays
public static class ArrayExtensions
{
public static IEnumerable<T> ToEnumerable<T>(this Array target)
{
foreach (var item in target)
yield return (T)item;
}
}
If you really, reaaaallly, reaaaaaallly want, you could construct something like this:
public static void Main(string[] args)
{
var area = new Tile[5, 5];
for (var j = 0; j < 5; j++)
for (var i = 0; i < 5; i++)
area[i, j] = new Tile() { height = (j + 1) * (i + 1), terrain = 99 };
Your linq:
// this copies the data over from your area-array into a new int[5,5] array using
// IEnumerable.Aggregate(...) with an emtpy seeded int[5,5] array and
// leverages Enumerable.Range() with integer division + modular to get
// the indices right
var onlyHeights = Enumerable
.Range(0, 25)
.Aggregate(new int[5, 5], (acc, i) =>
{
acc[i / 5, i % 5] = area[i / 5, i % 5].height;
return acc;
});
Test:
for (var j = 0; j < 5; j++)
for (var i = 0; i < 5; i++)
Console.WriteLine($"area.height {area[i, j].height} => {onlyHeights[i, j]}");
Console.ReadLine();
}
Output:
area.height 1 => 1
area.height 2 => 2
area.height 3 => 3
area.height 4 => 4
area.height 5 => 5
area.height 2 => 2
area.height 4 => 4
area.height 6 => 6
area.height 8 => 8
area.height 10 => 10
area.height 3 => 3
area.height 6 => 6
area.height 9 => 9
area.height 12 => 12
area.height 15 => 15
area.height 4 => 4
area.height 8 => 8
area.height 12 => 12
area.height 16 => 16
area.height 20 => 20
area.height 5 => 5
area.height 10 => 10
area.height 15 => 15
area.height 20 => 20
area.height 25 => 25
But thats just some nested for's in disguise.
And if you want a more generic LINQ-like method accepting higher dimensional arrays.
public static class ArrayExtensions
{
private static IEnumerable<int[]> CreatePermutations(int[] lengths, int pos = 0)
{
for (var i = 0; i < lengths[pos]; i++)
{
var newArray = (int[])lengths.Clone();
newArray[pos] = i;
if (pos + 1 >= lengths.Length)
{
yield return newArray;
continue;
}
foreach (var next in CreatePermutations(newArray, pos + 1)) yield return next;
}
}
public static Array Select<T,P>(this Array target, Func<T, P> func)
{
var dimensions = target.Rank;
var lengths = Enumerable.Range(0, dimensions).Select(d => target.GetLength(d)).ToArray();
var array = Array.CreateInstance(typeof(P), lengths);
var permutations = CreatePermutations(lengths);
foreach (var index in permutations)
{
array.SetValue(func((T)target.GetValue(index)), index);
}
return array;
}
}
Which you can call like.
var heightOnly = area.Select<Tile, int>(a => a.height);
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 months ago.
Improve this question
banknotes provided = 10 Dollar, 50 Dollar, 100 Dollar
Expected Result for 100 dollar bill with above bank notes.
I want to show the denomination exactly like below
5 x 10 + 1x 50
2 x 50
1 x 100
10 x 10
As you can see all the banknotes denomination total to 100 above
Let's split the problem in two:
Solve the exchange problem of total given notes (in descending order), starting from nominal at index.
Provide the solution in required format
Code:
private static IEnumerable<int[]> Solutions(int total, int[] notes, int index) {
int value = notes[index];
if (index == notes.Length - 1) {
if (total % value == 0)
yield return new int[] { total / value };
}
else
for (int i = total / value; i >= 0; --i)
foreach (int[] rest in Solutions(total - value * i, notes, index + 1))
yield return rest.Prepend(i).ToArray();
}
private static IEnumerable<string> Solve(int total, int[] notes) {
var items = notes.OrderByDescending(item => item).ToArray();
foreach (int[] solution in Solutions(total, items, 0))
yield return string.Join(" + ", solution
.Zip(items, (count, note) => (count, note))
.Where(pair => pair.count > 0)
.Select(pair => $"{pair.count} x {pair.note}"));
}
Demo:
int total = 170;
int[] notes = new int[] {10, 50, 100};
Console.Write(string.Join(Environment.NewLine, Solve(total, notes)));
Output:
1 x 100 + 1 x 50 + 2 x 10
1 x 100 + 7 x 10
3 x 50 + 2 x 10
2 x 50 + 7 x 10
1 x 50 + 12 x 10
17 x 10
Fiddle
Here is another (way less compact and cool than Dmitry's) solution, that uses recursion as you said. Basically I create a tree for each possible sum of the available banknotes that starts with the given amount at the root. For example, for your given amount of 100, and the given notes 10, 50, 100, I create the following pictured trees (and more), where the leaf values represent the individual banknotes that make up the total amount.
The leaf values then get transformed to your output, and possible duplicates (since different trees can be created from the same bank notes) are not printed out.
The following input:
int[] availableBanknotes = { 10, 50, 100 };
int amount = 100;
SolveRecursive(amount, availableBanknotes);
prints out:
10 x 10
1 x 50 + 5 x 10
2 x 50
1 x 100
The following input:
int[] availableBanknotes = { 10, 50, 100 };
int amount = 170;
SolveRecursive(amount, availableBanknotes);
prints out:
17 x 10
1 x 50 + 12 x 10
2 x 50 + 7 x 10
1 x 100 + 7 x 10
3 x 50 + 2 x 10
1 x 100 + 1 x 50 + 2 x 10
Here is the code:
private static List<string> Solutions = new List<string>();
private static void SolveRecursive(int amount, int[] availableBanknotes)
{
List<int> denomination = new List<int>();
for (int i = 0; i < availableBanknotes.Length; i++)
{
if (amount >= availableBanknotes[i])
{
ProvidedBanknotes(amount, availableBanknotes[i], availableBanknotes, new List<int>(denomination));
}
}
Solutions = new List<string>();
}
private static void ProvidedBanknotes(int amount, int currentBankNote, int[] availableBanknotes, List<int> denomination)
{
amount = amount - currentBankNote;
denomination.Add(currentBankNote);
if (amount == 0)
{
PrintSolution(denomination, availableBanknotes);
return;
}
for (int i = 0; i < availableBanknotes.Length; i++)
{
if(amount >= availableBanknotes[i])
{
ProvidedBanknotes(amount, availableBanknotes[i], availableBanknotes, new List<int>(denomination));
}
}
}
private static void PrintSolution(List<int> denomination, int[] availableBanknotes)
{
string solution = "";
for(int i = availableBanknotes.Length - 1; i >= 0; i--)
{
int currentVal = availableBanknotes[i];
int count = denomination.Where(temp => temp.Equals(currentVal))
.Select(temp => temp)
.Count();
if (count != 0)
{
if(solution.Equals(""))
{
solution = $"{count} x {currentVal}";
}
else
{
solution = solution + $" + {count} x {currentVal}";
}
}
}
if(!Solutions.Contains(solution))
{
Solutions.Add(solution);
Console.WriteLine(solution);
}
}
Given
var notes = new[] { 10, 50, 100 };
var total = 100;
You can use a LINQ Extension Method to create all possible combinations of notes and filter them to just combinations that could be used to create the total. I sort the notes in the combination descending so that the final answer will be output in descending order:
var possibleCombos = notes.Where(n => n <= total)
.AllCombinations()
.Select(c => c.OrderByDescending(n => n).ToList())
.Where(c => c.Sum() <= total && c.Aggregate(total-c.Sum(), (r, n) => r % n) == 0)
.OrderBy(c => c.Last());
While it doesn't apply to the example, the Aggregate expression ensures that impossible combinations aren't selected, such as trying to make { 50, 20 } yield 100.
For each possible combination, you can start with the total and then take away one of each note to ensure at least one of each note is in the answer. It then computes the number of additional notes needed for each denomination, starting with the largest. For each combination it outputs the number of each note in the format requested:
foreach (var combo in possibleCombos) {
var numberOfNotes = Enumerable.Repeat(1, combo.Count).ToList(); // one of each denomination
var remainder = total - combo.Sum(); // start by taking away one of each denomination
for (int j1 = 0; j1 < combo.Count; ++j1) {
numberOfNotes[j1] += remainder / combo[j1]; // take away all possible of each denomination
remainder = remainder % combo[j1];
}
Console.WriteLine(String.Join(" + ", numberOfNotes.Select((numberOfNote, j1) => $"{numberOfNote} x {combo[j1]}")));
}
The extension method is defined as:
public static class IEnumerableExt {
public static IEnumerable<IEnumerable<T>> AllCombinations<T>(this IEnumerable<T> start) {
IEnumerable<IEnumerable<T>> HelperCombinations(IEnumerable<T> items) {
if (items.IsEmpty())
yield return items;
else {
var head = items.First();
var tail = items.Skip(1);
foreach (var sequence in HelperCombinations(tail)) {
yield return sequence; // Without first
yield return sequence.Prepend(head);
}
}
}
return HelperCombinations(start).Skip(1); // don't return the empty set
}
}
NOTE: This only produces one possible solution for each combination of bills, the one that uses the maximum possible number of the largest denomination.
Here's my take on this:
public IEnumerable<List<int>> GetDenominations(List<int> denominations, int value) =>
GetDenominations(new List<int>(), denominations, value);
private IEnumerable<List<int>> GetDenominations(List<int> bills, List<int> denominations, int value)
{
int sum = bills.Sum();
if (sum == value)
{
yield return bills;
}
else if (sum < value && denominations.Any())
{
for (int i = 0; i < denominations.Count; i++)
{
List<int> denominations2 = denominations.Skip(i).ToList();
List<int> bills2 = bills.Append(denominations2.First()).ToList();
foreach (var result in GetDenominations(bills2, denominations2, value))
{
yield return result;
}
}
}
}
That produces all valid combinations of the denominations that add up the value passed.
I get the results like this:
IEnumerable<List<int>> results = GetDenominations(new List<int>() { 10, 50, 100 }, 170);
And formatting is just a little LINQ work:
string output =
String
.Join(
Environment.NewLine,
results
.Reverse()
.Select(xs =>
String
.Join(
" + ",
xs
.OrderByDescending(x => x)
.GroupBy(x => x)
.Select(x => $"{x.Count()} x {x.Key}"))));
That gives me:
1 x 100 + 1 x 50 + 2 x 10
3 x 50 + 2 x 10
1 x 100 + 7 x 10
2 x 50 + 7 x 10
1 x 50 + 12 x 10
17 x 10
I have some code to sort an array into ascending order
int[] array = new int[] { 4, 3, 5, 1 };
var result = array.GroupBy(x => x)
.OrderBy(g => g.Count())
.ThenBy(g => g.Key)
.SelectMany(g => g);
I would like to be able to count the number of steps required to complete the sort.
The specific question I am trying to solve is this:
You are given an unordered array consisting of consecutive integers [1, 2, 3, ..., n] without any duplicates. You are allowed to swap any two elements. You need to find the minimum number of swaps required to sort the array in ascending order.
Can I find the number of swaps used by LINQ?
Is it possible to get this?
So for example if the query had to swap 4 with 1 to get 1,3,5,4 then 5 with 4 to get 1,3,4,5 then this would be 2 steps.
This is how I came up. I couldn't find the way using it with LINQ however with our own Sorting Algorithm. I did something like this:
static void Main(string[] args)
{
ObservableCollection<int> array = new ObservableCollection<int>() {4,3,1,5 };
int steps = 0;
array.CollectionChanged+= (sender, e) =>
{
Console.WriteLine($"{e.Action} : {string.Join(",", array) }" );
steps++;
};
bool didSwap;
do
{
didSwap = false;
for (int i = 0; i < array.Count - 1; i++)
{
if (array[i] > array[i + 1])
{
int temp = array[i + 1];
array[i + 1] = array[i];
array[i] = temp;
didSwap = true;
}
}
} while (didSwap);
Console.WriteLine("Sorted Result :");
foreach(var item in array)
{
Console.WriteLine(item);
}
Console.WriteLine($"Total Swapps {steps / 2}");
Console.ReadLine();
}
This is the output:
I have a List of list. I want to revert this (rows become columns and columns become rows. I am able to invert it if number of elements are same in inner list. But if number of elements in inner list are different I am not able to do so.
So lets say I have this list
1 2 3 4
5 6 7 8
I get this output
1 5
2 6
3 7
4 8
But if I have input like this, then I receive errors
1
2 3 4
5 6 7
Here is the code,
var invertedRows = matrix.Select(row => row.Count).Concat(new[] {0}).Max();
var result = new Point3D[invertedRows][];
for (var i = 0; i < invertedRows; i++)
{
var invertedColumns = matrix[i].Count;
result[i] = new Point3D[invertedColumns];
for (var j = 0; j < invertedColumns; j++)
result[i][j] = matrix[j][i];
}
matrix.Clear();
matrix.AddRange(result.Select(row => row.ToList()));
Update: (moved first LINQ approach to the bottom since this is much better)
You can use this extension method:
public static List<List<T>> Pivot<T>(this List<List<T>> inputLists, bool removeEmpty, T defaultVal = default(T))
{
if (inputLists == null) throw new ArgumentNullException("inputLists");
if(removeEmpty && !object.Equals(defaultVal, default(T))) throw new ArgumentException("You cannot provide a default value and removeEmpty at the same time!", "removeEmpty");
int maxCount = inputLists.Max(l => l.Count);
List<List<T>> outputLists = new List<List<T>>(maxCount);
for(int i = 0; i < maxCount; i++)
{
List<T> list = new List<T>();
outputLists.Add(list);
for (int index = 0; index < inputLists.Count; index++)
{
List<T> inputList = inputLists[index];
bool listSmaller = inputList.Count <= i;
if (listSmaller)
{
if (!removeEmpty)
list.Add(defaultVal);
}
else
list.Add(inputList[i]);
}
}
return outputLists;
}
Usage:
List<List<int>> lists = new List<List<int>>();
lists.Add(new List<int> { 1 });
lists.Add(new List<int> { 2,3 });
lists.Add(new List<int> { 4,5,6 });
List<List<int>> result = lists.Pivot(true);
foreach(List<int> list in result)
Console.WriteLine(string.Join(",", list));
Output:
1,2,4
3,5
6
Old, accepted version that is less efficient and does not support different default values and removal of empty elements following:
public static List<List<T>> Pivot<T>(this List<List<T>> inputLists)
{
int maxCount = inputLists.Max(l => l.Count);
var result = Enumerable.Range(0, maxCount)
.Select(index => inputLists.Select(list => list.ElementAtOrDefault(index))
.ToList())
.ToList();
return result;
}
Note that it replaces all non existent indices with the default value of that type.
Test:
List<List<int>> lists = new List<List<int>>();
lists.Add(new List<int> { 1 });
lists.Add(new List<int> { 2,3 });
lists.Add(new List<int> { 4,5,6 });
List<List<int>> result = lists.Pivot();
foreach(List<int> list in result)
Console.WriteLine(string.Join(",", list));
Output:
1,2,4
0,3,5
0,0,6
well your input is not of the same length.
what do you expect to see in the first column of the output?
How does your code allow for this?
code should look something like this
List<List<int>> cols = new List<List<int>>();
cols.Add(new List<int>() { 1 });
cols.Add(new List<int>() { 2,3,4 });
cols.Add(new List<int>() { 5,6,7 });
int[][] result = new int[100][];
for (int i = 0; i < cols.Count; i++)
{
for (int j = 0; j < cols[i].Count; j++)
{
if (result[j] == null)
{
result[j] = new int[100];
}
if (cols[i].Count < j)
{
result[j][i] = 0;
} else
{
result[j][i] = cols[i][j];
}
}
}
If you debug your code you should find out easily where exactly is the problem. Probably something like calling 4th column from a 3 column array/list.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Combination of List<List<int>>
I have multiple Lists, could be 2 or 3 up to 10 lists, with multiple
values in them. Now what I need to do is to get a combination of all
of them.
For example, if I have 3 lists with the following values:
List 1: 3, 5, 7
List 2: 3, 5, 6
List 3: 2, 9
I would get these combinations
3,3,2
3,3,9
3,5,2
Etc..
Now the problem is I cannot do this easily because I do not know how many lists I have, therefore determine how many loops I need.
You could probably make that a lot easier, but this is what I had in mind just now:
List<List<int>> lists = new List<List<int>>();
lists.Add(new List<int>(new int[] { 3, 5, 7 }));
lists.Add(new List<int>(new int[] { 3, 5, 6 }));
lists.Add(new List<int>(new int[] { 2, 9 }));
int listCount = lists.Count;
List<int> indexes = new List<int>();
for (int i = 0; i < listCount; i++)
indexes.Add(0);
while (true)
{
// construct values
int[] values = new int[listCount];
for (int i = 0; i < listCount; i++)
values[i] = lists[i][indexes[i]];
Console.WriteLine(string.Join(" ", values));
// increment indexes
int incrementIndex = listCount - 1;
while (incrementIndex >= 0 && ++indexes[incrementIndex] >= lists[incrementIndex].Count)
{
indexes[incrementIndex] = 0;
incrementIndex--;
}
// break condition
if (incrementIndex < 0)
break;
}
If I’m not completely wrong, this should be O(Nm) with m being the number of lists and N the number of permutations (product of the lengths of all m lists).
you could make a List<List<yourValueType> mainlist in which you put all your lists.
then with a simple
int numberOfIterations = 1;
foreach(var item in mainlist)
{
numberOfIterations *= item.Count;
}
this would get the amount of iterations you would have to execute in total.
Non-recursive solution, works on any IEnumerables (not just lists) without solidifying them:
public static IEnumerable<IEnumerable<T>> Permutations<T>(
this IEnumerable<IEnumerable<T>> source)
{
// Check source non-null, non-empty?
var enumerables = source.ToArray();
Stack<IEnumerator<T>> fe = new Stack<IEnumerator<T>>();
fe.Push(enumerables[0].GetEnumerator());
while (fe.Count > 0)
{
if (fe.Peek().MoveNext())
{
if (fe.Count == enumerables.Length)
yield return new Stack<T>(fe.Select(e => e.Current));
else
fe.Push(enumerables[fe.Count].GetEnumerator());
}
else
{
fe.Pop().Dispose();
}
}
}
Not very efficient but very easy to understand approach might be to solve this task recursively. Consider a method which computes permutations for N lists. If you have such a method then you can easily compute permutations for N+1 lists by combining all permutation of N lists with every number in the last list. You should also handle corner case which permutations of 0 lists. Then implementation seems to be straightforward:
IEnumerable<IEnumerable<T>> GetAllPermutations<T>(IEnumerable<IEnumerable<T>> inputLists)
{
if (!inputLists.Any()) return new [] { Enumerable.Empty<T>() };
else
{
foreach (var perm in GetAllPermutations(inputLists.Skip(1)))
foreach (var x in inputLists.First())
yield return new[]{x}.Concat(perm);
}
}
As an alternative, following rawlings general idea the following should work
public static IEnumerable<IEnumerable<T>> Permutations<T> (this IEnumerable<IEnumerable<T>> underlying)
{
var enumerators = new Queue<IEnumerator<T>>(underlying.Select(u => u.GetEnumerator())
.Where(enumerator => enumerator.MoveNext());
Boolean streaming = enumerators.Any();
if(streaming)
{
IEnumerable<T> result;
IEnumerator<T> finalEnumerator = enumerators.Dequeue();
Func<Boolean,Boolean> finalAction = b => b ? b : finalEnumerator.MoveNext();
Func<Boolean,Boolean> interimAction =
enumerators.Reverse()
.Select(enumerator => new Func<Boolean,Boolean>(b => b ? b : (enumerator.MoveNext() ? true : enumerator.ResetMove())))
.Aggregate((f1,f2) => (b => f1(f2(b)));
enumerators.Enqueue(finalEnumerator);
Func<Boolean,Boolean> permutationAction =
interimAction == null ?
finalAction :
b => finalAction(interimAction(b));
while(streaming)
{
result = new Queue<T>(enumerators.Select(enumerator => enumerator.Current))
streaming = permutationAction(true);
yield return result;
}
}
private static Boolean ResetMove<T>(this IEnumerator<T> underlying)
{
underlying.Reset();
underlying.MoveNext();
return false;
}
Is it possible to use LINQ to transform a flat array of doubles containing coordinate tuples (x, y),i.e. [x0,y0, ..., xN, yN] to an array of half the length containing the same coordinates wrapped in a Point-class, i.e. [p0, ..., pN]?
Preferably .NET 3.5, but also interrested in 4.0.
You can use .Batch from Jon Skeet's morelinq:
IEnumerable<Point> points = coordinates.Batch(2,pair => new Point(pair.ElementAt(0), pair.ElementAt(1)));
In all honestly, the simplest solution is probably using a method (here with ints):
public IEnumerable<Point> GetPoints(int[] coordinates)
{
for (int i = 0; i < coordinates.Length; i += 2)
{
yield return new Point(coordinates[i], coordinates[i + 1]);
}
}
double[] arr = { 1d, 2d, 3d, 4d, 5d, 6d };
var result = arr.Zip(arr.Skip(1), (x, y) => new Point(x, y))
.Where((p, index) => index % 2 == 0);
EDIT: In this LINQ statement, the collection is looped through twice, which is not efficient. A better solution is using a for loop. And Zip is new in C# 4.0, an alternative is:
var result = arr.Select((n, index) => new Point(n, arr[index + 1]))
.Where((p, index) => index % 2 == 0);
This will just loop once and will work in 3.5
int[] arr = new int[] { 1, 1, 2, 2, 3, 3 };
if (arr.Length % 2 != 0)
throw new ArgumentOutOfRangeException();
Point[] result = arr
.Where((p, index) => index % 2 == 0)
.Select((n, index) => new Point(n, arr[index * 2 + 1]))
.ToArray();
And here's another (possibly more "pure") option:
public static class Program
{
public static IEnumerable<Point> ToPoints(this IEnumerable<int> flat)
{
int idx = 0;
while(true)
{
int[] parts = flat.Skip(idx).Take(2).ToArray();
if (parts.Length != 2)
yield break;
idx += 2;
yield return new Point(parts[0], parts[1]);
}
}
static void Main(string[] args)
{
int[] arr = new int[] { 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7 };
var x = arr.ToPoints().ToArray();
return;
}
}
Sure. I haven't compiled /run, so it may have typos, but the gist should be right.
var newArray = source.Aggregate(new List<double>,
(xCoords, next) =>
{
if(xCoords.length % 2 == 0) {
xCoords.Add(next);
}
return xCoords;
},
xCoords => xCoords
).Zip(source.Aggregate(new List<double>,
(yCoords, next) =>
{
if(yCoords.length % 2 != 0) {
yCoords.Add(next);
}
return yCoords;
},
yCoords => yCoords
, (x, y) => new Point(x, y)
).ToArray();