Related
array = [[1, 2], [13, 14], [4, 5], [80, 30], [12, 14], [10, 90], [3, 2], [6, 9], [1, 5], [4, 5], [5, 9], [4, 3], [13, 12]]
//expected
output = [[1, 2], [13, 14], [4, 5], [80, 30], [10, 90], [3, 2], [6, 9], [4, 5], [5, 9], [4, 3], [13, 12]]
You can consider the subarrays as lines, for example, [1,2] would be a line connected from point 1 to point 2. Therefore, [1,2],[3,2],[4,3],[4,5],[4,3] would correlate with several short lines that connect point 1 to point 5, because there is a line connected from point 1 to 2, 2 to 3, 3 to 4, and 4 to 5.
If the array contains a larger single line that is point 1 to point 5, it should be filtered out. This is to remove all longer lines that already have their points defined in more shorter lines. What algorithm could be used to solve this?
I have tried the code below at https://codepen.io/Maximusssssu/pen/jOYXrNd?editors=0012
The first part outputs all subarrays in ascending order for readability, whereas for the second part, I have tried the include() method to check whether a node is present in the subarray, and get its position.
array = [[1, 2], [13, 14], [4, 5], [80, 30], [12, 14], [10, 90], [3, 2], [6, 9], [1, 5], [4, 5], [5, 9], [4, 3], [13, 12]]
array_ascending_arr = [];
for (let i = 0; i < array.length; i++) {
let subarrayy = array[i].sort(function(a, b) {
return a - b
});
array_ascending_arr.push(subarrayy);
}
console.log(array_ascending_arr) // output all subarrays in ascending order back into array
for (let k = 1; k < 5; k++) {
for (let m = 0; m < array.length; m++) {
for (let i = 1; i < 2; i++) {
if (array_ascending_arr[m].includes(k) == true) {
console.log(m)
}
}
}
console.log(".......")
}
the main idea is to calculate the difference in number of intermediate elements and not in value
if we have [[1,2],[14,10],[4,6],[9,2] that makes a sequence = [1,2,4,6,9,10,14] (sorted)
return delta values:
[1,2] -> d:1
[9,2] -> d:3 // the 9 is three positions away from the 2
the principle is therefore to process starting from the least distant values towards those most distant
(the other sorting criteria are secondary and are mainly useful for debugging)
note: duplicate pairs are also eliminated
const
test1 = [[1,2],[13,14],[4,5],[80,30],[12,14],[10,90],[3,2],[6,9],[1,5],[4,5],[5,9],[4,3],[13,12]]
, test2 = [[1,2],[4,5],[30,80],[12,18],[10,90],[2,3],[6,9],[1,5],[4,6],[5,9],[3,4],[12,13],[12,14],[14,15],[15,18]]
;
console.log('test1:\n', JSON.stringify( combination( test1 )))
console.log('test2:\n', JSON.stringify( combination( test2 )))
function combination(arr)
{
let
nodes = arr.flat().sort((a,b)=>a-b).filter((c,i,{[i-1]:p})=>(c!==p))
, sets = nodes.map(g=>[g])
, bads = []
;
arr // i:index, s:start(min), e:end(max), d: delta
.map(([v0,v1],i) => ({i,s:Math.min(v0,v1),e:Math.max(v0,v1), d:Math.abs(nodes.indexOf(v0) - nodes.indexOf(v1))}))
.sort((a,b) => (a.d-b.d) || (a.s-b.s) || (a.e-b.e) || (a.i-b.i) )
.forEach(({i,s,e,d}) =>
{
let
gS = sets.find(n=>n.includes(s))
, gE = sets.find(n=>n.includes(e))
;
if (gS === gE) { bads.push(i) }
else { gS.push(...gE); gE.length=0 }
})
//console.log( sets.filter(a=>a.length).map(a=>JSON.stringify(a)).join(' - ') )
return arr.filter((x,i)=>!bads.includes(i))
}
.as-console-wrapper { max-height: 100% !important; top: 0; }
.as-console-row::after { display: none !important; }
You could try for an adjacency list. My understanding of the algorithm is if two pairs share an edge they will combine to form a new edge until all sets are unique.
So from what I understand, you're trying to remove any set of numbers that encompasses a range greater than any that are smaller. The following code should do this:
array.filter(pair => {
// Get the smaller and larger numbers from the pair
const [small, big] = pair.sort((a,b) => a-b)
// Check if this pair is larger than any others
return !array.some(test => {
const [testSmall, testBig] = test.sort((a,b) => a-b)
return big > testBig && small < testSmall
})
})
Note that this won't remove duplicates.
If you don't mind your subarrays being reordered in the final array, you can simplify it a bit by sorting them all at the beginning:
array
.map(pair => pair.sort((a,b) => a-b))
.filter(([s, b], _, arr) => !arr.some(([ts, tb]) => b>tb && s<ts))
Presently I have a multidimensional array that I want to loop over. All I want is to push the inner elements to an empty array. But What I'm getting is totally different from the expected output.
All have done so far below
const prices = [ [2, 20], [7, 50], [12, 100], [17, 40], [22, 32], [27, 25 ] ];
function addItemToCart() {
let new_items = [] // I want this array to be [2, 7, 12, 17, 22, 27]
// looping outer array elements
for(let i = 0; i < prices.length; i++) {
for(let j = 0; j < prices[i].length; j++) {
new_items.push(prices[i][j])
console.log(new_items);
}
}
}
addItemToCart()
Use map: const newItems = prices.map(price => price[0])
Do you want to completely flatten your array, or just take the first item from each inner array and copy that to the new array?
If you want to flatten it completely, you can do it like this:
const newArray = prices.reduce((res, arr) => [...res, ...arr], []);
If you only want the first item from each inner array, I would recommend the solution that Konstantin suggested.
You don't need loops for that:
const prices = [ [2, 20], [7, 50], [12, 100], [17, 40], [22, 32], [27, 25 ] ];
const toAdd = [].concat.apply([], prices);
console.log(toAdd);
I have an array of arrays and I want to check if there is a tie between the second elements and then return the first element of the last array that makes a tie.
for example this should return 4. (the first element in the last array that has a second element that makes a tie)
var optionsArray = [[1, 10], [2, 10], [3, 10], [4, 10], [6, 14]];
It is quite simple, you need to iterate over your source array, check if the given item matches the criteria, and save it to result if it does. Now if any other item does match the criteria, result's value will be overwritten with the new matching item.
var optionsArray = [[1, 10], [2, 10], [3, 10], [4, 10], [6, 14]];
var result;
optionsArray.forEach(function(item) {
if(item[1] == 10) {
result = item;
}
});
console.log(result);
You can create a simple find function that iterates the array backwards, and returns as soon as a condition callback returns true.
var optionsArray = [[1, 10], [2, 10], [3, 10], [4, 10], [6, 14]];
function find10(s) {
return s[1] === 10;
}
function findFromTheEnd(arr, cb) {
var l = arr.length;
while(l--) { // iterate backwards
if(cb(arr[l])){ // if the callback returns true
return arr[l]; // return the item
}
}
return null; // return null if none found
}
var result = findFromTheEnd(optionsArray, find10);
console.log(result);
You can use reduceRight() and return array.
var arr = [[1, 10], [2, 10], [3, 10], [4, 10], [6, 14]];
var result = arr.reduceRight(function(r, e) {
if(e[1] == 10 && !r) r = e;
return r;
}, 0)
console.log(result)
You can also use for loop that starts from end and break on first match.
var arr = [[1, 10], [2, 10], [3, 10], [4, 10], [6, 14]];
var result;
for (var i = arr.length - 1; i >= 0; i--) {
if (arr[i][1] == 10) {
result = arr[i]
break;
}
}
console.log(result)
A classic for in the reserve order with a break seems enough :
var optionsArray = [[1, 10], [2, 10], [3, 10], [4, 10], [6, 14]];
var elementFound;
for (var i = optionsArray.length-1; i >=0; i--) {
if(optionsArray[i].item[1] == 10) {
elementFound = optionsArray[i].item[1];
break;
}
}
If elementFound is not undefined, it refers to the found array.
Rather than considering this as a multidimensional array problem, think of it as an array includes problem nested in an array search problem;
const aarr = [1, 2, 3, 4];
aarr.includes(3); // true
aarr.includes(10); // false
// and
const barr = ['hello', 'world'];
barr.find(item => item[0] === 'h'); // "hello"
barr.find(item => item[3] === 'l'); // "hello"
barr.find(item => item[1] === 'z'); // undefined
So to nest these,
const carr = [[1, 2, 3, 4], [4, 5, 6, 7]];
carr.find(arr => arr.includes(4)); // [1, 2, 3, 4]
carr.find(arr => arr.includes(6)); // [4, 5, 6, 7]
Next, we've reduced the whole problem down to "how to do this in reverse?"
You've a few options depending on how you want to implement it, but a simple way to do it is a shallow clone arr.slice() followed by a reverse arr.reverse() (we use the clone so there are no side-effects of reverse on the original array)
carr.slice().reverse().find(arr => arr.includes(4)); // [4, 5, 6, 7]
If you're working with an index, remember that you'll need to transform those too; -1 is fixed, otherwise transformed_index = arr.length - original_index - 1
Here is how you might implement the reverse of some of the Array methods
const optionsArray = [[1, 10], [2, 10], [3, 10], [4, 10], [6, 14]];
// index 0 1 2 3 4
function arrLast(arr, comparator, method = 'find', transform = x => x) {
return transform(arr.slice().reverse()[method](comparator), arr);
}
const findLast = (arr, comparator) => arrLast(arr, comparator);
const findLastIndex = (arr, comparator) => arrLast(arr, comparator, 'findIndex', (i, arr) => i === -1 ? -1 : arr.length - i - 1);
arrLast(optionsArray, arr => arr.includes(10)); // [4, 10]
findLastIndex(optionsArray, arr => arr.includes(10)); // 3
If you have to make comparisons among array items and you need to cut short once you are satisfied a while loop is ideal. Accordingly you may do as follows;
var arr = [[1, 10], [2, 10], [3, 10], [4, 10], [6, 14]],
i = 0,
result;
while (arr[i][1] === arr[++i][1]);
result = arr[i-1][0]
console.log(result);
I have an array which is like that: [[0, 50], [1, 40], [2, 30], [3, 20], [5, 10]]
And I want to accumulative the second values: [[0, 50], [1, 90], [2, 120], [3, 140], [5, 150]]
I tried the code part below which works for one dimensional arrays, but it doesn't work for 2d arrays. Is it possible to accumulate it by using reduce function? Or is there different way to do it?
var array1 = [[0, 50], [1, 40], [2, 30], [3, 20], [5, 10]];
var newArray1 = [];
array1.reduce(
function (previousValue, currentValue, currentIndex) {
return newArray1[currentIndex] = [currentIndex, (previousValue[1] + currentValue[1])];
}, 0
);
You can use map() with optional thisArg parameter
var array1 = [[0, 50], [1, 40], [2, 30], [3, 20], [5, 10]];
var result = array1.map(function(e) {
this.num = (this.num || 0) + e[1];
return [e[0], this.num];
}, {});
console.log(result);
Use Array#reduce method
var array1 = [
[0, 50],
[1, 40],
[2, 30],
[3, 20],
[5, 10]
];
// initialize as the array of first element in original array
var newArray1 = [array1[0].slice()];
array1
// get remaining array element except first
.slice(1)
// iterate over the array value to generate result array
.reduce(function(arr, v, i) {
// copy the array element if you don't want to refer the old
v = v.slice();
// add previous array value
v[1] += arr[i][1];
// push updated array to result array
arr.push(v);
// retur the updated array
return arr;
// set initial value as array which contains first element(array) copy
},newArray1);
console.log(newArray1)
UPDATE 1: Another method with less code
var array1 = [
[0, 50],
[1, 40],
[2, 30],
[3, 20],
[5, 10]
];
var newArray1 = [array1[0].slice()];
array1.slice(1).reduce(function(arr, v, i) {
arr.push([v[0], v[1] + arr[i][1]]);
return arr;
}, newArray1);
console.log(newArray1)
UPDATE 2 : Much more reduced version without using Array#slice method.
var array1 = [
[0, 50],
[1, 40],
[2, 30],
[3, 20],
[5, 10]
];
var newArray1 = array1.reduce(function(arr, v, i) {
// push value to array add value only if `arr` contains any element
arr.push([v[0], v[1] + (arr.length && arr[i - 1][1])]);
return arr;
// set initial value as an empty array
}, []);
console.log(newArray1)
Just for fun lets invent a new array functor, Array.prototype.extend() This works like opposite to the reduce. It takes an array and extends it starting from the last item by utilizing a provided callback. When the callback returns undefined it sops extending. Let see how we can have fun with it in this particular case;
Array.prototype.extend = function(cb){
var len = this.length + 1,
res = cb(this[len-1], len-1, this);
return res ? this.extend(cb) : this;
};
var arr = [[0, 50], [1, 40], [2, 30], [3, 20], [5, 10]],
cb = function(e,i,a){
return i === 0 ? a.push(arr[i])
: i < arr.length ? a.push([arr[i][0], arr[i][1] + a[i-1][1]])
: void 0;
};
result = [].extend(cb);
console.log(result);
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
flatten two array with an if statment
I have array1 and array2
I want array3
<script>
var array1 = [[5,10],[6,10],[7,10],[8,10],[9,10]];
var array2 = [[1,10],[2,10],[3,10],[4,10],[5,40],[6,40]];
// only the second number will add if they are different
// [5,10] + [5,40]
// [6,10] + [6,40]
// array3 = [[1,10],[2,10],[3,10],[4,10],[5,50],[6,50],[7,10],[8,10],[9,10]];
</script>
This is a proposal with Array#forEach() in a single loop and a temporary object.
var array1 = [[5, 10], [6, 10], [7, 10], [8, 10], [9, 10]],
array2 = [[1, 10], [2, 10], [3, 10], [4, 10], [5, 40], [6, 40]],
array3 = [];
array2.concat(array1).forEach(function (a) {
if (!this[a[0]]) {
this[a[0]] = [a[0], a[1]];
array3.push(this[a[0]]);
return;
}
if (this[a[0]][1] !== a[1]) {
this[a[0]][1] += a[1];
}
}, Object.create(null));
document.write('<pre>' + JSON.stringify(array3, 0, 4) + '</pre>');
Solution with for loop
var array1 = [[5, 10], [6, 10], [7, 10], [8, 10], [9, 10]],
array2 = [[1, 10], [2, 10], [3, 10], [4, 10], [5, 40], [6, 40]],
array3 = [],
i,
temp = Object.create(null),
array = array2.concat(array1);
for (i = 0; i < array.length; i++) {
if (!temp[array[i][0]]) {
temp[array[i][0]] = [array[i][0], array[i][1]];
array3.push(temp[array[i][0]]);
continue;
}
if (temp[array[i][0]][1] !== array[i][1]) {
temp[array[i][0]][1] += array[i][1];
}
}
document.write('<pre>' + JSON.stringify(array3, 0, 4) + '</pre>');