I populate a 2d array with a while loop, but I need to stop the push when the 1st column contains 3 different unique value.
the start is something like this
var maxunique;
var i = 0;
while (countunique(arr) != maxunique) {
// my code that push data into array
arr[i].push(RandomNumber(1,8));
arr[i].push(i+1);
i++;
}
function countunique(arr)
{
// function here
}
function RandomNumber(min,max)
{
return Math.floor(Math.random()*(max-min+1)+min);
}
This return that value
arr: [ [ 4, 1 ],
[ 7, 2 ],
[ 5, 3 ],
[ 5, 4 ],
[ 3, 5 ],
[ 1, 6 ],
[ 7, 7 ],
[ 8, 8 ],
[ 5, 9 ],
[ 5, 10 ] ]
Whell the idea about the expected result is
arr: [ [ 4, 1 ],
[ 7, 2 ],
[ 5, 3 ] ]
you can see that the push is interrupted after the first 5, that is the 3 unique value in array
I don't know how to do it, and I don't know if is better do to with a while or a for loop.
Any Idea?
In the loop where you are populating the 2D array, have the array sent to a check function that determines if 3 unique elements are present as the first elements in the individual array. Here is the code for check function, it returns true if 3 unique elements are not yet present, once it finds 3 unique elements it returns false.
var a = []; //;
var i = 0;
while (check(a)) {
a[i]=[];
a[i].push(RandomNumber(1, 42));
a[i].push(i + 1);
i++;
}
function RandomNumber(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
function check(arr) {
var length = arr.length;
var tmp = [];
for (var j = 0; j < length; j++) {
if (tmp.indexOf(arr[j][0]) === -1) {
tmp.push(arr[j][0]);
}
if (tmp.length === 3) {
return false;
}
}
return true;
}
console.log('test: ', a);
console.log('check: ', check(a));
You could use one object to store each first number as property and check in each iteration of while loop if any value in that object is equal 3. If it is you can break from loop. I used random number for first number.
var ar = [];
var obj = {}
while (true) {
var firstNum = parseInt(Math.random() * 5) + 1;
ar.push([firstNum, 1]);
obj[firstNum] = (obj[firstNum] || 0) + 1;
var stop = Object.keys(obj).find(function(e) {
return obj[e] == 3;
});
if (stop) break;
}
console.log(obj);
console.log(ar);
You could implement a function which stores the number of the first column as a property in a object and increments a counter if that number does not exist in that object.If the counter is equal to 3 then there are 3 unique elements,then stop the array push and break out of the loop.
Here is an example code.
var arr = ['-15, 1',
'-15, 2' ,
'2,3' ,
'2, 4' ,
'2, 5',
'77, 6','22,3' ];
function unique(array) {
var arr = [],x,y,obj = {},count = 0,arr1;
for (i = 0; i < array.length ; i++) {
arr1 = array[i].split(',');
x = arr1[0] * 1;
y = arr1[1] * 1;
if (count === 3) {
break;
}
array.push([x,y]);
if (!obj[x]) {
obj[x] = 1;
count++;
}
}
}
This implements a real push:
var yourarray={
arr:[],
push:function(obj){
for(a=0;a<this.obj.length){
let count=0;
for(i=0;i<this.arr.length;i++){
if(obj[a]!=this.arr[i][a]){
count++;
if(count==3){
break;
}
}
}
}
this.arr.push(obj);
};
};
Now you can do:
yourarray.push([0,1,2]);
And access it like:
alert(yourarray.arr);
However, accessing yourarray directly isnt possible anymore
Related
I am trying to find 3 or more matching items in array but it is only matching the first 3 and none matching for the rest of the array. If anyone could help would be great :)
var grid = [2,2,2,5,5,5,3,3,3,3];
checkResults();
function checkResults(){
var list_matches = []; // store all matches found
var listcurrent = []; // store current
var maxitems = 3;
var last = -1; // last cell
for(let j =0; j < grid.length; ++j){
let item = grid[j];
// check if last is null
if(last == -1){
// add first item
listcurrent.push(item);
last = item;
console.log("Added: "+item);
continue;
}
let wasMatch = false;
// check match
if(item == last){
wasMatch = true;
listcurrent.push(item);
last = item;
console.log("Added Match: "+item);
}
if(!wasMatch){
console.log("Not matched: " + item);
if(listcurrent.length >= maxitems){
list_matches.push(listcurrent);
}
// reset to null
last = -1;
listcurrent = [];
}
}
console.log(list_matches);
console.log("Cols: " + grid.length);
}
Expected Results: from [2,2,2,5,5,5,3,3,3,3];
0: 222
1: 555
2: 3333
Current output is:
0: 222 and thats it
You could take a temporary array for collecting the same values and push this array if the length has the wanted minimum length.
function getMore(array, min) {
var result = [],
temp;
array.forEach((v, i, a) => {
if (v !== a[i - 1]) return temp = [v];
temp.push(v);
if (temp.length === min) result.push(temp);
});
return result;
}
console.log(getMore([2, 2, 2, 5, 5, 5, 3, 3, 3, 3], 3));
you can do something like this:
var grid = [ 1, 1, 2, 3, 4, 5 ];
var hashMap = {};
for( var i = 0; i < grid.length; i++ ) {
if( hashMap.hasOwnProperty( grid[i] ) ) {
hashMap[ grid[i] ]++;
} else {
hashMap[ grid[i] ] = 1;
}
}
it will helps you.
//toLowerCase for get unique on words, not on character. if i ignore this, it will return two words=> developers. and developers
//first Split and join for remove '.' character form text and finally last split is for convert string to an Array of words that splited by Space character
let uniqWords = Array.from(new Set(text));
//using Set to get unique words and convert it to Array to do more on Array.
let count = {};
// declare varriable for store counts of words.
uniqWords.map(item => {
count[item] = text.filter(elem => {
//create property with the name of words and filter common words to an Array
return elem == item
}).length
//get Array length for get words repeated count.
})
console.table(count)
//log Result into Console
Another solution using Array.prototype[reduce/map/filter]
const someArray = [2, 2, 2, 5, 5, 5, 3, 3, 3, 3, 9, 9];
console.log(aggregate(someArray));
function aggregate(arr) {
return arr
// retrieve unique values
.reduce((acc, val) => !acc.includes(val) && acc.concat(val) || acc, [])
// use unique values to map arr values to strings
// if number of matches >= 3
.map(val => {
const filtered = arr.filter(v => v == val);
return filtered.length > 2 ? filtered.join("") : false
})
// filter non falsy values
.filter(val => val);
}
This question already has answers here:
Breaking out of an inner foreach loop
(2 answers)
Closed 3 years ago.
I'm using labels in my code. But javascript keeps complaining 'label is not a statement.'
function firstDuplicate(a) {
array1 = [];
b = a;
var val;
var valIndex;
var iCount = 0;
a.forEach(function(aLoop, aIndex) {
b.forEach(function(bLoop, bIndex) {
if (bLoop == aLoop) {
val = bLoop;
iCount = iCount++;
valIndex = bIndex;
} else { //I want to move evaluation to where I have label 'loop1'
break loop1;
}
});
obj = {
val: val,
index: valIndex,
count: iCount
};
array1.push(obj);
val = 0;
iCount = 0;
valIndex = 0;
loop1:
});
return array1;
}
console.log(firstDuplicate([2, 1, 3, 5, 3, 2]));
actual result is crashing; expecting js object be populated with 1) elements that occur > 1; index of the last occurence of the element; and count
You can't break out of a Array.forEach function.
You are using the post increment operator which won't work in this case. Here iCount = iCount++; will evaluate iCount as 0.
You also need to find the previous object inserted when there is a duplicate found in array1 and then increment its count. You can do this by using Array.find.
If a duplicate is found by comparing the aIndex and bIndex then we are pushing a new object into array1 with count as 1. If it is again encountered later we simply find the inserted object and increase the count and record the index in an array.
function firstDuplicate(a) {
array1 = [];
a.forEach(function(aLoop, aIndex) {
a.forEach(function(bLoop, bIndex) {
if (bIndex > aIndex && bLoop === aLoop) {
let dup = array1.find(o => o.val === bLoop);
if(!dup){
obj = {
val: bLoop,
index: [aIndex, bIndex],
count: 1
};
array1.push(obj);
}else{
dup.count = dup.count + 1;
dup.index = !dup.index.includes(bIndex) ? [bIndex].concat(dup.index) : dup.index;
}
}
});
});
return array1;
}
console.log(firstDuplicate([2, 1, 3, 5, 3, 2, 2, 3]));
Goal: given an array of mixed types determine the number of elements at each level. If there are two sub-arrays at the same level, each of their elements count towards to the total number of elements at that level.
Approach:
Array.prototype.elementsAtLevels = function( level, levelData ) {
if ( level == undefined ) { level = 0; } else { level += 1 }
if ( levelData == undefined ) { levelData = {}; }
if ( levelData[level] == undefined ) { levelData[level] = this.length} else { levelData[level] += this.length }
this.map(function(e, i) {if (Array.isArray(e)){ e.elementsAtLevels(level, levelData) }})
return levelData
}
Test case:
[
1, // 0: 1
1, // 0: 2
1, // 0: 3
1, // 0: 4
[ // 0: 5
2, // 1: 1
2, // 1: 2
2 // 1: 3
],
[ // 0: 6
[ // 1: 4
3, // 2: 1
3 // 2: 2
],
[ // 1: 5
[ // 2: 3
4 // 3: 1
]
]
]
].elementsAtLevels()
// Object [ 6, 5, 3, 1 ]
Question:
Is there a more efficient way to calculate this?
I wrote something very similar to what you have, and in a very rudimentary benchmark, it ran in a little under half the time.
let a = [1,1,1,1,[2,2,2],[[3,3],[[4]]]];
Array.prototype.elementsAtLevels2 = function (level, lData) {
if (!level || !lData) {
level = 0;
lData = {};
}
if (!(level in lData)) {
lData[level] = this.length;
} else {
lData[level] += this.length;
}
this.forEach(function (v) {
if (Array.isArray(v))
v.elementsAtLevels2(level + 1, lData);
});
return lData;
}
console.log(a.elementsAtLevels2());
I'm guessing the main performance increase might be from the forEach vs map, map creates a new array, where forEach does not.
Edit
Here it is in JSBin
Here is my take on it. It resembles yours but it doesn't change the prototype and it uses an array instead of an object for return.
function arrayCounter(arr, level, levelData) {
if (level === void 0) {
level = 0;
}
if (levelData === void 0) {
levelData = [];
}
//Set default value for level
if (levelData[level] === void 0) {
levelData[level] = 0;
}
//Count length
levelData[level] += arr.length;
//Loop through list items
for (var i = 0; i < arr.length; i++) {
var value = arr[i];
//If array, perform a subcount
if (Array.isArray(value)) {
levelData = arrayCounter(value, level + 1, levelData);
}
}
return levelData;
}
//TEST
var data = [1, 1, 1, 1, [2, 2, 2],
[
[3, 3],
[
[4]
]
]
];
console.log(arrayCounter(data));
This thing performs about the same as yours, but at least it gives correct results:
function elementsAtLevel( array, result = [], level = 0 ){
result[level] = (result[level] || 0) + array.length
level++
for( const el of array ){
if( Array.isArray(el) )
elementsAtLevel(el, result, level)
}
return result
}
console.log( elementsAtLevel([1,1,1,1,[2,2,2],[[3,3],[[4]]]]) )
By correct I mean consistent: you counted subarrays as elements on the first level, but not any other.
Here's a prototype version:
Array.prototype.elementsAtLevel = function( result = [], level = 0 ){
result[level] = (result[level] || 0) + this.length
level++
for( const el of this ){
if( Array.isArray(el) )
el.elementsAtLevel(result, level)
}
return result
}
console.log( [1,1,1,1,[2,2,2],[[3,3],[[4]]]].elementsAtLevel() )
this recursive function should do the work
let arr = [1,1,1,1,[2,2,2],[[3,3],[[4]]]];
Array.prototype.elementsAtLevels = function(){
return this.reduce((acc, el, index, currentArray) => {
if(Array.isArray(el)){
return acc.concat(el.elementsAtLevels());
}
return [currentArray.length];
}, [])
}
console.log(arr.elementsAtLevels());
I have one nested array for example
var arr = [
[0,1,2,3,4],
[0,1,2,3],
[0,1,2,3,4],
[0,1]
];
How to remove N items from end or from beginning using lodash?
For example if I remove 6 elements from beginning, I want result to be:
var arr = [
[1,2,3],
[0,1,2,3,4],
[0,1]
];
and if I remove 1 from end, I need result to be:
var arr = [
[0,1,2,3,4],
[0,1,2,3],
[0,1,2,3,4],
[0]
];
I hope i was clear. Lodash is not necessary.
This is my code:
function removeFromTop(group, count) {
for (var i = 0; i < group.length; i++) {
for (var x = 0; x < group[i].chatItems.length; x++) {
if(count) {
group[i].chatItems.splice(x, 1);
if(!group[i].chatItems.length) {
group.splice(i, 1);
};
count--;
} else {
break;
}
};
};
return group;
}
function removeFromBottom(group, count) {
for (var i = group.length - 1; i >= 0; i--) {
for (var x = group[i].chatItems.length - 1; x >= 0; x--) {
if(count) {
group[i].chatItems.splice(x, 1);
if(!group[i].chatItems.length) {
group.splice(i, 1);
};
count--;
} else {
break;
}
};
};
return group;
}
You could shift the inner array for each item count from the beginning and pop the values from the end. For the first you could use Array#reduce and for the other Array#reduceRight
function removeFromStart(array, n) {
var copy = JSON.parse(JSON.stringify(array));
return copy.reduce(function (r, a) {
while (n && a.length) {
a.shift();
n--;
}
a.length && r.push(a);
return r;
}, []);
}
function removeFromEnd(array, n) {
var copy = JSON.parse(JSON.stringify(array));
return copy.reduceRight(function (r, a) {
while (n && a.length) {
a.pop();
n--;
}
a.length && r.push(a);
return r;
}, []).reverse();
}
var array = [[0, 1, 2, 3, 4], [0, 1, 2, 3], [0, 1, 2, 3, 4], [0, 1]];
console.log(JSON.stringify(removeFromStart(array, 6)));
console.log(JSON.stringify(removeFromEnd(array, 6)));
.as-console-wrapper { max-height: 100% !important; top: 0; }
using Lodash function .drop you can drop very first element(s) of an array or else can specify n element(s) default value is 1. same way .dropRight for the end element(s).
var arr = [
[0,1,2,3,4],
[0,1,2,3],
[0,1,2,3,4],
[0,1]
];
// remove 1 element front of 2D Array
var resultFront= arr.map(function(value,index) { return _.drop(value); });
console.log(resultFront);
// remove 1 element from End of 2D Array
var resultEnd= arr.map(function(value,index) { return _.dropRight(value); });
console.log(resultEnd);
// remove 1 element front and end of 2D Array
var resultFrontEnd = arr.map(function(value,index) { return _.dropRight(_.drop(value)); });
console.log(resultFrontEnd);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
var arr = [
[0,1,2,3,4],
[0,1,2,3],
[0,1,2,3,4],
[0,1]
];
console.log(arr);
console.log('------------------------');
// remove 1 element front of 2D Array
var resultFront= arr.map(function(value,index) { return _.drop(value); });
console.log('Remove 1 element from front') ;
console.log(resultFront);
// remove 1 element from End of 2D Array
var resultEnd= arr.map(function(value,index) { return _.dropRight(value); });
console.log('Remove 1 element from end') ;
console.log(resultEnd);
// remove 1 element front and end of 2D Array
var resultFrontEnd = arr.map(function(value,index) { return _.dropRight(_.drop(value)); });
console.log('Remove 1 element from front & End') ;
console.log(resultFrontEnd);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>
You can simply do as follows;
var arr = [[0,1,2,3,4],[0,1,2,3],[0,1,2,3,4],[0,1]],
r = [],
n = 6,
res = arr.reduce((r,sa) => r.n > sa.length ? (r.n -= sa.length, r)
: (r.push(sa.slice(r.n)), r.n = 0, r), (r.n = n, r));
console.log(res);
I use a state variable r.n within the initial array in the reduce operation. You may or may not chose to delete it afterwards.
This question already has answers here:
How to get the difference between two arrays in JavaScript?
(84 answers)
Closed 8 years ago.
Assume that I have this array:
a = [
[2823832908, 10071920],
[5384625228, 10924221],
[8488934028, 313411415],
[2823828588, 10071580],
[5224682868, 14919881],
[8155986228, 560217208],
[3458951628, 10071570],
[6382592388, 25064430],
[5021452668, 10924221],
[8827673748, 59397160],
[8647215588, 26343621]
]
and this array:
b = [
[8488934028, 313411415],
[8647215588, 26343621]
]
How can I get a new array that contains the values in array a that are not in array b, or how can I remove the values in array b from array a?
Create an empty result array.
Iterate over a, select its current element i.e. [2823832908, 10071920]
Compare current element for equality against each element of b , to compare equality
you can use JSON.stringify or .join to create string representation of arrays.
If the current element does not match any element of b, appent it to result array.
Repeat.
a = [
[2823832908, 10071920],
[5384625228, 10924221],
[8488934028, 313411415],
[2823828588, 10071580],
[5224682868, 14919881],
[8155986228, 560217208],
[3458951628, 10071570],
[6382592388, 25064430],
[5021452668, 10924221],
[8827673748, 59397160],
[8647215588, 26343621]
];
b = [
[8488934028, 313411415],
[8647215588, 26343621]
];
var result = [];
a.forEach(
function(elem,idx,arr)
{
var sig = JSON.stringify(elem);
var match = false;
for(var i=0;i<b.length;i++)
{
if(sig == JSON.stringify(b[i]))
{
match = true;
break;
}
}
if(match === false)
{
result.push(elem);
}
}
);
console.log(result);
demo : http://jsfiddle.net/Ag39M/4/
This is a bit tricky, principally because two arrays are not equal in Javascript, even if they have exactly the same keys.
You have to compare them manually, for example with this function by Tim Down.
You will then have to loop through the values in first array and compare them to every value in the second array.
The code might look like this:
var filtered = [];
// loop through every element in a
a.forEach(function(elA) {
// loop through every element in b
// if the elA is identical to any elB, some will immediately return true
// if elA is not identical to any elB, it will return false
var found = a.some(function(elB) {
return arraysIdentical(elA, elB);
});
// if we didn't find any equal ones, we'll add elA to the filtered array
if (!found) {
filtered.push(elA);
}
});
Note that this relies upon Array#forEach and Array#some. If you need to support older browsers, you'll need to shim them, with the polyfill code in those links.
Here's an implementation using undescore.js.
function diff(a1, a2) {
return _.filter(a1, function(e1) {
return !_.some(a2, function(e2) {
return _.isEqual(e1, e2);
});
});
}
Example:
var a = [ [ 1, 2 ], [ 3, 4 ], [ 5, 6, 7 ], [ 8 ], [ 9 ] ];
var b = [ [ 1, 2 ], [ 8 ], [ 9 ] ];
console.log(diff(a, b));
// [ [ 3, 4 ], [ 5, 6, 7 ] ]
function arra_diff(a, b)
{
var arr=[], diff=[];
for(var i=0;i<a.length;i++)
arr[a[i]]=true;
for(var i=0;i<b.length;i++)
if(arr[b[i]]) delete arr[b[i]];
else arr[b[i]]=true;
for(var k in arr)
diff.push(k);
return diff;
}
or
function arra_diff(d, c) { /* d=a,c=b */
for (var b = [], e = [], a = 0; a < d.length; a++) {
b[d[a]] = !0;
}
for (a = 0; a < c.length; a++) {
b[c[a]] ? delete b[c[a]] : b[c[a]] = !0;
}
for (var f in b) {
e.push(f);
}
return e;
};