-1

I wanted to change the rows into columns of an array.

[
  [1],
  [1,2],
  [1,2,3],
  [4,2,3],
  [4,5,3],
  [4,5,6]
]

to [ [1,1,1,4,4,4], [2,2,2,5,5], [3,3,3,6] ]

I tried

var res = [];

    for(i in this.fields) {

        for(j in this.fields[i].value) {

            if(i === 0) res[j] = [];
            res[j][i] = this.fields[i].value[j];

        }

    }

this gives me empty set.

Joey Hipolito
  • 3,108
  • 11
  • 44
  • 83

3 Answers3

3

Create this function:

function transpose(arr) {
        return Object.keys(arr[0]).map(function (c) {
            return arr.map(function (r) {
                return r[c];
            });
        });
    }

and then:

var transposedArray = transpose(originalArray);

Pedro Justo
  • 3,969
  • 1
  • 17
  • 21
1

What you're asking looks a little weird because you have different lengths and you're ignoring undefined values, but it is still achievable.

Don't use for..in loops for Array, use a normal for. Also, you'll need to know how many items you'll have in your new parent Array, which is the max of the lengths of the original child Arrays.

var arrR = [ // will refer to "down" and "across" as in this literal
        [1],
        [1, 2],
        [1, 2, 3],
        [4, 2, 3],
        [4, 5, 3],
        [4, 5, 6]
    ];
function r2c(arr) {
    var arrC = [], // next get the longest sub-array length
        x = Math.max.apply(Math, arr.map(function (e) {return e.length;})),
        y = arr.length,
        i, j;
    for (i = 0; i < x; ++i) {   // this is the loop "down"
        arrC[i] = [];
        for (j = 0; j < y; ++j) // and this is the loop "across"
            if (i in arr[j])
                arrC[i].push(arr[j][i]);
    }
    return arrC;
}
var arrC = r2c(arrR);
/* [
    [1, 1, 1, 4, 4, 4],
    [2, 2, 2, 5, 5],
    [3, 3, 3, 6]
] */

You should still consider if you're happy with [[1], [1, 2], [1]] becoming [[1, 1, 1], [2]], which I would consider unexpected (the position of 2 is completely lost), but seems to be what you intend.

Paul S.
  • 64,864
  • 9
  • 122
  • 138
1

Similar to Pauls but doesn't need to get the max length first:

function transpose(arr) {

  // Loop over arrays as long as one has values
  // Arrays should be contiguous, may fail if sparse
  for (var result = [], i=0, more; more; i++) {
    more = false;

    // Get the ith element of each array (if there is one)
    for (var j=0, jLen=arr.length; j<jLen; j++) {

      // Don't add missing members
      if (arr[j].hasOwnProperty(i)) {

        // Add array for result if not already there
        result[i] = result[i] || [];

        // Do transpose
        result[i][j] = arr[j][i];

        // Only keep going while there is data
        more = true;
      }
    }
  }
  return result;
}

BTW, a fixed version of your original function is:

function transpose2(fields) {
    // Make sure the result array is initialised
    var res = [];

    // Don't forget to keep counters local - declare them
    // I've removed *this* as it's a plain function, use it if 
    // it's an instance method
    for(var i in fields) {

        // Values are read directly, there is no "value" accessor
        for(var j in fields[i]) {

            // Don't rely on order of enumeration - may not start at 0
            if(!res[j]) res[j] = [];

            // Do the transpose
            res[j][i] = fields[i][j];
        }
    }
    return res;
}

But as noted above, for..in is not liked for arrays, particularly as there are many libraries that extend built-ins like Array.prototype so you will traverse those properties too. But if you're cool with that, this is a good way to deal with sparse arrays. You can add a hasOwnProperty test to avoid inherited enumerables.

Note also that the order of enumeration isn't necessarily from '0' or in any particular order, hence changed way of initialising res[j].

RobG
  • 142,382
  • 31
  • 172
  • 209