Changing rows to columns javascript - javascript

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.

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);

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.

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].

Related

Best way to loop through an array and return the sub arrays that match the first 2 values

Let's say I have 4 arrays:
var arrays = [
[1, 2, 1],
[1, 3, 4],
[1, 2, 3],
[0, 2, 2]
];
And I want to return the child/sub arrays that start with both 1 and 2, what type of loop would I need?
Currently, this is what I have:
var arrays = [
[1, 2, 1],
[1, 3, 4],
[1, 2, 3],
[0, 2, 2]
];
var selected = [1, 2]; // These are the values that need to match
var result = [];
for (var i = 0; i < selected.length; i++) {
for (var j = 0; j < arrays.length; j++) {
if (arrays[i][j] === selected[i]) {
result.push(arrays[i]);
}
}
}
When there's more than 1 value in the selected array, it seems to return all the ones that match 2 on the second index, so the result would be:
[
[1, 2, 1],
[1, 2, 3],
[0, 2, 2]
]
The loop needs to ensure that on the second iteration it's making sure the first value is still true, as my intended result would be:
[
[1, 2, 1],
[1, 2, 3]
]
Please someone help me, I've had my head trying hundreds of different loop and checks variations for 2-3 days.
Thanks so much!!
Jake
Your current code pushes to the result array whenever any given index matches between arrays and selected. Instead you will need to reverse your loops and iterate over selected for every sub array and check if every element matches, if not break the inner loop and don't push.
const arrays = [
[1, 2, 1],
[1, 3, 4],
[1, 2, 3],
[0, 2, 2],
];
const selected = [1, 2]; // These are the values that need to match
const result = [];
for (let i = 0; i < arrays.length; i++) {
let match = true;
for (let j = 0; j < selected.length; j++) {
if (arrays[i][j] !== selected[j]) {
match = false;
break;
}
}
if (match) {
result.push(arrays[i]);
}
}
console.log(result);
A more modern solution would be to use filter() with a nested every() call on selected.
const arrays = [
[1, 2, 1],
[1, 3, 4],
[1, 2, 3],
[0, 2, 2],
];
var selected = [1, 2];
const result = arrays.filter(arr => selected.every((n, i) => n === arr[i]));
console.log(result);
Here is another approach where you turn both arrays to string and check it those inner arrays start with selected array.
var arrays = [
[1, 2, 1],
[1, 3, 4],
[1, 2, 3],
[0, 2, 2]
];
var selected = [1, 2];
const result = arrays.filter(e => e.toString().startsWith(selected.toString()))
console.log(result)
Let's try to put your condition into words. That way, an implementation may come to mind more easily.
A short wording may be: "Take all arrays that match (rather: start with) a certain sub-array." In code, it may look like this:
const arrays = [
[1, 2, 1],
[1, 3, 4],
[1, 2, 3],
[0, 2, 2]
];
const selection = [1, 2];
const result = filterArrays(arrays, selection);
console.log(result);
function filterArrays(arrays, selection) {
const selectedArrays = [];
for (let i = 0; i < arrays.length; ++i) {
const array = arrays[i];
const subarray = array.slice(0, selection.length); // Get starting sub-array
if (compareArrays(subarray, selection)) {
selectedArrays.push(array);
}
}
return selectedArrays;
}
/*Ignore; helper function*/
function compareArrays(array1, array2) {
if (array1.length !== array2.length) return false;
const length = array1.length;
for (let i = 0; i < length; ++i) {
if (array1[i] !== array2[i]) return false;
}
return true;
}
.as-console-wrapper {max-height:100%!important}
Another, more specific wording may be: "Take all arrays that match a selection at an index." Note that we only reworded the "match a sub-array" part. I believe this is what you tried.
Refer to pilchard's answer for an implementation. Note that their implementation assumes the arrays in arrays to be at least the same length as selected.
I see you used var instead of the preferred modern let/const declarators. Here's a short outline of their differences:
let/const declarators:
Block-scoped.
Narrower scope means less name-space pollution.
More similar to declarators in other well-known languages:
Variables of these declarators cannot be used before their declaration (see TDZ).
var declarator:
Function-scoped.
Hoisted and with no TDZ, resulting in this (perhaps confusing) behaviour:
Variables declared with var can be used even before their declaration.
Duplicate declarations are allowed since they are effectively the same.
Also, JavaScript has different kinds of for-loops:
for-loop: The for-loops you used are this kind. It is the most versatile kind.
for...of-loop: A loop to iterate over an iterable object (see iterators). For example, arrays are iterable, so you can get its values with a for...of-loop:
const values = [1, 2, 3];
let sum = 0;
for (const value of array) {
sum += value;
}
console.log(sum); // -> 6
for...in-loop: A loop to iterate over enumerable properties of an object. It is easily confused with a for...of-loop, but MDN's example demonstrates the differences understandably.
In my code example above, the for-loop in filterArrays() can be replaced with a for...of-loop to better convey my intention: To iterate over all arrays in arrays, disregarding their index:
for (let i = 0; i < arrays.length; ++i) {
const array = arrays[i];
// ...
}
// Same as
for (const array of arrays) {
// ...
}

breaking an array into subsets

I am trying to get this function to split an array into subsets. each subset is to have numbers that are equal to the previous or within 1 from the previous number.
The example I have below should return two subsets but it returns {0, 1, 2, 3} instead. Any idea on what I am doing wrong? Also, is there a better way to dynamically create an array for each new subset? Thanks
function max_tickets() {
var arr = [4, 13, 2, 3];
var myarr = arr.sort(function(a, b){return a-b});
for(var i = 0; i<myarr.length; i++){
var iplus = i+1;
if(i === i || i === iplus){
newArr= [];
newArr.push(i);
}else if (i !== i || i !== iplus){
arr2 =[];
arr2.push(i);
}
}
}
What you are trying to do is usually called "partitioning". The generic version of the problem is to partition an array into sub-arrays using some "rule", or predicate, or condition, which specifies which partition a particular element is supposed to go into, or specifies that it should go into a new partition.
The pseudo code for doing this would be:
To partition an array:
Initialize the resulting array
For each element in the array
If that element starts a new chunk
Create a new empty chunk in the resulting array
Add the element to the most recent chunk
Return the result
This can be expressed in JS quite straightforwardly as
function partition(array, fn) {
return array.reduce((result, elt, i, a) => {
if (!i || !fn(elt, i, a)) result.push([]);
result[result.length - 1].push(elt);
return result;
}, []);
}
Now we need to write the function saying when a new partition should start:
// Is the element within one of the previous element?
function close(e, i, a) {
return Math.abs(e - a[i-1]) > 1;
}
We can now partition the array with
partition([[4, 13, 2, 3], close)
This should work.
function max_tickets() {
var arr = [4, 13, 2, 3];
var myarr = arr.sort(function (a, b) { return a - b });
arrSubsets = [];
arr1 = [];
for (var i = 0; i < myarr.length; i++) {
if (myarr[i - 1] === undefined) {
arr1.push(myarr[i]);
continue;
}
if (myarr[i] - myarr[i - 1] <= 1) {
arr1.push(myarr[i]);
}
else {
arrSubsets.push(arr1);
arr1 = [];
arr1.push(myarr[i]);
}
}
if (arr1.length > 0)
arrSubsets.push(arr1);
}
max_tickets();
Based on your questions:
Any idea on what I am doing wrong?.
Inside of your loop you are using i as if it is the value of the array, but the loop goes from 0 to the value of myarr.length in your particular case 4, so that makes the value of i to be 0, 1, 2, 3.
As you can see you are using the values of the index to compare, instead of using the values of the array in order to use the values of the array you must specify the arrayname[index], in your case myarr[i] that will give you the values: 4, 13, 2, 3.
Also, is there a better way to dynamically create an array for each new subset?
Yes you can create an array inside of another array dynamically inside of a loop:
var b = [];
for(var i = 0; i < 10; i++){
b.push(['I am' + i, i]);
}
As you can see in the previous example I'm creating an array inside of the b array so once the loop finishes the b array will have 10 arrays inside of it with 2 elements each.

Callbacks & manipulating arrays but getting undefined back

Practicing callbacks & higher ordered function & found this question online.
var merge = function(array1, array2, callback){
//your code here.
}
var x = merge([1, 2, 3, 4], [5, 6, 7, 8], function(a, b){
return a + b;
});
//x should now equal [6, 8, 10, 12].
Here's my take on this problem.
var merge = function(array1, array2, callback){
for(var i = 0; i < array1.length; i++) {
callback(array1[i], array2[i]);
}
}
var x = merge([1, 2, 3, 4], [5, 6, 7, 8], function(a, b){
return a + b;
});
When I console.log(x), the console returns "undefined" so I'm guessing it has to do w/ the value of x not being an array. I can see that the math is being done correctly though, for when I change "return a + b" to "console.log(a + b)" I get the right numbers but just not in array form. Can anyone point me towards the right direction?
You are calling the callback, but you are ignoring the value returned by it. You should accumulate all the values in an array and your should return the array from merge.
For example,
function merge(array1, array2, callback) {
// Define an array object to accumulate the results from `callback`
var result = [];
for (var i = 0; i < array1.length; i++) {
// Accumulate the result of `callback` in `result` array
result.push(callback(array1[i], array2[i]));
}
// Return the `result` array
return result;
}
Note: If the arrays are of different sizes then running the loop based on array1's length will not be correct always. So, you might want to either
go with the smallest length of two arrays and ignore elements from the longer array
or use a default value for the elements of the shorter array.
If you choose go with the first method, then you just need to adjust the loop condition, like this
var minLen = Math.min(array1.length, array2.length);
for (var i = 0; i < minLen; i++) {
...
If you choose to go with the second method, then you need to run till the maximum of two arrays and use default values, like this
var maxLen = Math.max(array1.length, array2.length);
for (var i = 0; i < maxLen; i++) {
result.push(callback(array1[i] || 0, array2[i] || 0));
}
Here, if the value of array1[i] returns undefined (if the index is not found in an array, undefined will be returned), it means that array1 is shorter than array2, so the default value 0 will be used.

Removing specific Arrays out of multidimensional arrays

I have this array, but not in any guaranteed order:
[ [2,1], [2,2], [2,3], [3,1], [3,2], [4,1], [4,2], [4,3], [4,4], [5,1], [5,2] ]
I need to cycle through it, match the ones with the same arr[0] value, and then remove the one with the highest value at arr[1]. It should end up looking like this:
[ [2,1], [2,2], [3,1], [4,1], [4,2], [4,3], [5,1] ]
I'm not sure exactly how to iterate through this accurately. Most places I have seen ways to filter complex objects, or remove single values from one-dimensional arrays.
I have only really gotten into using arrays in the last few days. Thanks for the help!
Okay I have two solutions. version1 is basic and could use some optimizing while version2 should be faster with bigger, evenly distributed lists.
If you're only going to have a few items, use one. It only has a few lines of code, so it won't be a distraction. If you have a big array and it'll be pretty evenly distributed, then use two.
I actually did a test with the sample data, and version2 has less iterations than version1. V1 ran 11 times in the outer loop, and 79 times in the inner loop. V2 ran 11 times in the first outer loop, 4 times in the second one. The inner loop of the second loop ran 11 times, and the loop inside that ran only 7 times. So the total iterations of v2 was about 40% of v1. When I double the items, v2 only uses 30% of the iterations.
Version2 has a couple of other potential advantages.
I believe Array.push has a higher performance cost than Array[index] =. If that's true, then you know that newAry will have a final length of the origianl array's length - the length of the indicies array length. So you can initialize newAry with that length, keep a counter variable, and then do something like newAry[counter++] = someVal.
There was some discussion if you wanted to keep a result if there was only one. If that is the case, it is easy to do a check at the start of the second loop: if (iVal.length == 1) // add to newAry else do j,k loops.
Version 1
function version1(ary) {
var newAry = [];
var iVal, jVal;
for (var i = 0, il = ary.length; i < il; i++) {
iVal = ary[i];
for (var j = ary.length - 1; j >= 0; j--) {
if (i != j) {
jVal = ary[j];
if (iVal[0] == jVal[0] && iVal[1] < jVal[1]) {
newAry.push(iVal);
break;
}
}
}
}
return newAry;
}
Version 2
function version2(ary) {
var indices = [];
var values = [];
var newAry = [];
var iVal,
index,
highestFound,
lowFound;
for (var i = 0, il = ary.length; i < il; i++) {
var iVal = ary[i];
if ((index = indices.indexOf(iVal[0])) == -1) {
indices.push(iVal[0])
values.push([ iVal[1] ]);
index++;
}
else {
values[index].push(iVal[1])
};
}
for (var i = 0, il = values.length; i < il; i++) {
iVal = values[i];
highestFound = false;
for (var j = 0, jl = iVal.length; j < jl; j++) {
if (!highestFound) {
lowFound = false;
for (var k = j + 1, kl = iVal.length; k < kl; k++) {
if (iVal[j] < iVal[k]) {
lowFound = true;
newAry.push([indices[i], iVal[j]]);
k = kl;
}
}
if (!lowFound) {
highestFound = true;
}
}
else {
newAry.push([indices[i], iVal[j]]);
}
}
}
return newAry;
}
jsFiddle
jsFiddle with Counters
Based on what you've given so far, here's the code I came up with:
var foo = [
[2, 1],
[2, 2],
[2, 3],
[3, 1],
[3, 2],
[4, 1],
[4, 2],
[4, 3],
[4, 4],
[5, 1],
[5, 2]
],
temp = [];
foo.forEach(function (value, index) {
if (typeof temp[value[0]] === 'undefined') {
temp[value[0]] = {
highestValue: value[1],
position: index
};
} else {
if (temp[value[0]].highestValue < value[1]) {
temp[value[0]].highestValue = value[1];
temp[value[0]].position = index;
}
}
});
temp.forEach(function(value, index) {
delete foo[value.position];
});
Do note that if you have in foo for instance [6,1], it will be deleted as well.
Making use of the excellent lodash.js library:
var ary = [ [2,1], [2,2], [2,3], [3,1], [3,2], [4,1], [4,2], [4,3], [4,4], [5,1], [5,2] ];
var results = _(ary)
// Group by the first value
.groupBy(function(pair) {
return pair[0];
})
// Turn the groups into arrays
.map(function(group) {
// Sort by the second value
var sorted = _.sortBy(group, function(pair) {
return pair[1];
});
// Keep all but the highest value
return _.take(sorted, sorted.length-1);
})
// Remove the groupings
.flatten(true)
// Unwrap the results
.value();
console.log(results);
jsFiddle: http://jsfiddle.net/dmillz/BhSDT/
I hope that helps!

How to get subset of two arrays in javascript?

What I am trying to do is if I have Array
a = {1,2,3,4};
b = {1,2};
Then I want subset array as c = {3,4};
Can anybody help me?
a = [1, 2, 3, 4]
b = [2, 1, 5]
comp = a.filter(function(e) { return b.indexOf(e) < 0 })
see Array.filter and Array.indexOf for more details and degradation options.
I'm not aware of any built-in way to do this, you basically have to loop through c and check whether each element is in a and, if so, remove it. The Array#indexOf method can help you with checking, but not all implementations have it (though most do). Removal can be via Array#splice.
So:
var a, c, index;
a = [1, 2];
c = [1, 2, 3, 4];
for (index = c.length - 1; index >= 0; --index) {
if (a.indexOf(c[index]) >= 0) {
c.splice(index, 1);
}
}
...and then either supply your own implementation of Array#indexOf if your environment doesn't support it, or use a library like Prototype that supplies it for you (jQuery gives it to you as well, but through its own jQuery.inArray function). If doing it yourself:
if (!Array.prototype.indexOf) {
(function() {
Array.prototype.indexOf = Array_indexOf;
function Array_indexOf(elm) {
var index;
for (index = 0; index < this.length; ++index) {
if (this[index] === elm) {
return index;
}
}
return -1;
}
})();
}
Note that adding to the Array prototype as above can be dangerous when done with poorly-written code code that makes assumptions about the environment. Specifically, code that treats for..in as though it loops through array element indexes (it doesn't, it looks through object property names) will get messed up if you add to the Array prototype. (That's probably why jQuery doesn't do it.)
Live example
Assuming that you're after the relative complement of b in a.
function complement(a, b) {
// convert A to an associative array
var myHash = {};
for (var i = 0; i < a.length; ++i) {
myHash[a[i]] = 1;
}
// remove the elements that exist in B
for (var i = 0; i < b.length; ++i) {
delete myHash[b[i]];
}
// what's left is A \ B
// assumes that no-one broke Array by adding new properties to the prototype
return Object.keys(myHash);
}
// test
var a = [1, 2, 3, 4];
var b = [1, 2];
var c = complement(a, b);
alert(c);
This should scale well for larger arrays, since it uses hash table indexing rather than linear searches to remove the unwanted elements.
Here is another solution which uses Array.filter() and Array.includes()
function arrayDifference(a, b) {
return a.filter((x) => !b.includes(x));
}
const a = [1, 2, 2, 2, 3, 4]
const b = [1, 2]
arrayDifference(a,b) // returns [3, 4]

Categories

Resources