-6

Suppose, that I have such jagged array (3 dimensions).

int[][][] tab = new int[][][] 
{
     new int[][]
     {
         new int[] {1, 2, 3},
         new int[] {4, 5, 6}
     },
     new int[][]
     {
         new int[] {7, 8, 9},
         new int[] {10, 11, 12}
     }
 };

I want to sum it over first dimension. I want to get:

new int[][] 
{
    new int[] {1+7, 2+8, 3+9},
    new int[] {4+10, 5+11, 6+12}
};

I want to sum it over second dimension.

new int[][] 
{
    new int{1+4, 2+5, 3+6},
    new int{7+10, 8+11, 9+12}
}

How to do those two things? I don't want loops, but rather LINQ expression.

  • 4
    `"I don't want loops, but rather LINQ expression"` -- What do you think LINQ is doing under the hood? – maccettura Feb 26 '18 at 22:46
  • 2
    You don't have multi-dimensional arrays, you have *jagged* arrays. A 3-dimensional array would look like `int[3,3,3]`. – NightOwl888 Feb 26 '18 at 22:47
  • 2
    Also, this code wouldn't even compile – maccettura Feb 26 '18 at 22:47
  • @maccettura Outside of a missing semicolon and a few missing brackets on the last array initializer, what about it would be a problem? – Servy Feb 26 '18 at 23:00
  • @Servy you must have seen after the recent edit. OP had `float` in the array before – maccettura Feb 26 '18 at 23:01
  • @maccettura Ah, that would indeed be a problem. – Servy Feb 26 '18 at 23:01
  • @maccettura Of course LINQ uses loops, but I meant, that I do not want CODE, that would go with loops through array. Will not compile? Maybe, did not check, but I think, that this, what I want to do is clear enough. – Piotr Bródka Feb 26 '18 at 23:02
  • 1
    My point being, if you know how to do this with loops just do it with loops. Dont force yourself to use LINQ if you dont understand it yet, you aren't optimizing anything by using LINQ. – maccettura Feb 26 '18 at 23:04
  • @maccettura, sorry, I did not see this float before, anyway, treat it as a pesudocode – Piotr Bródka Feb 26 '18 at 23:04
  • @maccettura I know how to do it with loops, but I want my code to be shorter - that is why I posted this question – Piotr Bródka Feb 26 '18 at 23:05
  • 3
    *I know how to do it with loops, but I want my code to be shorter* - What code do you want to be shorter? You haven't posted any looping code. – NightOwl888 Feb 26 '18 at 23:06
  • @maccettura I am beginner at LINQ, I have used it in very simplest situations, but I got stucked on this example. That is why I am asking - to learn something new – Piotr Bródka Feb 26 '18 at 23:06
  • 1
    @PiotrBródka Why would you expect a LINQ solution to be shorter? I would suspect that it would be dramatically more complex and lengthy. Regardless, if you already know how to do this, then apparently you don't actually have a problem; you have a working solution. If you just want your working solution code reviewed, you could ask on Code Review if others can think of ways to improve on it. – Servy Feb 26 '18 at 23:08
  • @NightOwl888 I did not write the code to sum it yet, because I predicted that it would be too long. If this, what I want achieve is not clear for you, say it, I will explain the problem more thoroughly. – Piotr Bródka Feb 26 '18 at 23:09
  • 1
    @PiotrBródka we all know what you are trying to do, we are simply saying that you should use loops for this and not try to jam a square peg in to a round hole (i.e use LINQ where it's not needed or can be needlessly complex). If your goal is to learn LINQ, asking strangers on the internet to do the work for you certainly won't help you learn – maccettura Feb 26 '18 at 23:12
  • @maccettura Is not asking strangers for help with things that you want to learn a main idea behind StackOverflow? – Piotr Bródka Feb 26 '18 at 23:17
  • 5
    You’ve not asked for _help_, you’ve asked for someone to do the work for you. You’ve included no attempt to solve this in your question, you’ve stipulated to us that you only want LINQ answers despite that not being the best option. You’re expected to make some attempt at solving the problem. This is why you’re required to include a [MCVE] with your question. – maccettura Feb 26 '18 at 23:19
  • 1
    The problem is under-specified. Jagged arrays are thus called because they are *jagged*, but your examples are nicely *rectangular*. What happens if you have an empty array in there? Or one that has 6 elements instead of 3? – Eric Lippert Feb 26 '18 at 23:42
  • As far as using LINQ is concerned, my advice is: write the logic *very carefully* using loops and then for each loop, ask yourself: *what is the logical task this loop is doing to the sequence of items?* Then replace each loop by a sequence operator that does the same thing, moving from inner loops to outer loops. See my answer here for some thoughts on this process. https://stackoverflow.com/questions/48549898/converting-nested-loops-into-linq/48550241#48550241 – Eric Lippert Feb 26 '18 at 23:44
  • @EricLippert Good point with jagged arrays. – Piotr Bródka Feb 26 '18 at 23:48

2 Answers2

1

This is a lot like the APL Reduction operator, which has a cool feature of letting you reduce over any dimension (e.g. +/tab versus +/[1]tab).

Over the first dimension, LINQ has an equivalent already, the Aggregate function. With some other extension functions, you can use it to do what you want:

public static class Ext {
    public static int[] Add(this int[] v1, int[] v2) => v1.Zip(v2, (v1v, v2v) => v1v+v2v).ToArray();
    public static int[][] Add(this int[][] a1, int[][] a2) => a1.Zip(a2, (a1r, a2r) => a1r.Add(a2r)).ToArray();

    public static TSource Reduce<TSource>(this IEnumerable<TSource> source, Func<TSource, TSource, TSource> func) => source.Aggregate(func);
    public static IEnumerable<T> Reduce2<T>(this IEnumerable<IEnumerable<T>> src, Func<T, T, T> op) => src.Select(s => s.Reduce(op));
}

I renamed Aggregate to Reduce to keep with the APL theme.

With the Reduce function, you can reduce across the first dimension, adding the 2D arrays:

var ans1 = tab.Reduce((a1, a2) => a1.Add(a2));

With the Reduce2 function, you can reduce across the second dimension, adding the 1D arrays:

var ans2 = tab.Reduce2((a1, a2) => a1.Add(a2)).ToArray();

Since I wrote Reduce/Reduce2 to be generic on IEnumerable, you have to convert the Reduce2 answer back to an array.

NetMage
  • 26,163
  • 3
  • 34
  • 55
0

Since jagged arrays are used, The length of smallest array within each respective group is used for indexing to avoid IndexOutOfRangeException:

// I want to sum it over first dimension.
var firstDimensionSums = tab
    .Aggregate((a, b) => Enumerable.Range(0, Math.Min(a.Length, b.Length))
        .Select(i0 => Enumerable.Range(0, Math.Min(a[i0].Length, a[i0].Length))
            .Select(i1 => a[i0][i1] + b[i0][i1])
            .ToArray())
        .ToArray());

// I want to sum it over second dimension.
var secondDimensionSums = tab
    .Select(nested => nested
        .Aggregate((a,b) => Enumerable.Range(0, nested.Min(x => x.Length))
            .Select(index => a[index] + b[index])
            .ToArray()))
    .ToArray();
Xiaoy312
  • 14,292
  • 1
  • 32
  • 44