This question already has answers here:
Closed 11 years ago.
Possible Duplicates:
Simplest code for array intersection in javascript
How to merge two arrays in Javascript
There are three arrays:
var items = Array(523,3452,334,31,5346);
var items_used = Array(3452,31,4123);
var items_new = Array();
First one is general, second is the items currenly in use. Third one includes all the items from the first array, witch are not mentioned in second.
How do I remove from the first array items, witch are used in second, and write the result to the third array?
We should get items_new = Array(523, 334, 5346). 3452 and 31 are removed, because they are mentioned in second array.
You could do this:
var items = Array(523,3452,334,31,5346);
var items_used = Array(3452,31,4123);
var items_compared = Array();
$.each(items, function(i, val){
if($.inArray(val, items_used) < 0)
items_compared.push(val);
});
That's it
Why not a simple for loop?
for(var j = 0; j < items.length; j++)
{
var found = false;
for(var k = 0; k < items_used.length; k++)
{
if(items_used[k] == items[j])
{
found = true;
break;
}
}
if(!found)
items_compared.push(items[j]);
}
As a faster solution maybe :
var j, itemsHash = {};
for (j = 0; j < items.length; j++) {
itemsHash[items[j]] = true;
}
for (j = 0; j < itemsUsed.length; j++) {
itemsHash[itemsUsed[j]] = false;
}
for (j in itemsHash) {
if (itemsHash[j]) {
itemsCompared.push(j);
}
}
runs in O(n) time, with a little more memory.
Basically I would make the third have all elements in the first, then loop through the second array removing all of those elements found in the first.
var items_compared = items;
for(int i = 0; i < items_used.length; ++i)
{
var indx = $.inArray(items_used[i], items_compared);
if(indx != -1)
items_compared.splice(indx, 1);
}
Related
The code below is not giving me the expected result.
It's to compare rows from two ranges and, although the second range's last row equals the one from the first range, it gives me false as the result.
var entryValuesCom = sheet.getRange(7, 1, LastRowSource, 9).getValues();
var dbDataCom = dbSheet.getRange(2, 1, dbSheet.getLastRow(), 9).getValues();
var entryVlArray = new Array();
var dbArray = new Array();
for (var r = 0; r < entryValuesCom.length; r++) {
if (entryValuesCom[r][0] != '' && entryValuesCom[r][5] != 'Daily Ledger Bal') {
entryVlArray.push(entryValuesCom[r]);
}
}
for (var a = 0; a < dbDataCom.length; a++) {
if (dbDataCom[a][1] != '' && dbDataCom[a][8] == bank) {
dbArray.push(dbDataCom[a]);
}
}
var duplicate = false;
loop1:
for (var x = 0; x < entryVlArray.length; x++) {
loop2:
for (var j = 0; j < dbArray.length; j++) {
if (JSON.stringify(entryVlArray) == JSON.stringify(dbArray)) {
duplicate = true;
break loop1;
}
}
}
Here's a snapshot of how the array is coming:
I've tried it using .join(), but still...
This is for thousands of rows, so is this going to do well performance wise?
I believe your goal as follows.
You want to compare the arrays of entryVlArray and dbArray using Google Apps Script.
When the duplicated rows are existing between entryVlArray and dbArray, you want to output duplicate = true.
Modification points:
When your script is modified, at if (JSON.stringify(entryVlArray) == JSON.stringify(dbArray)) {, all 2 dimensional arrays are compared. I think that this might be the reason of your issue. From your script, I think that it is required to compare each element in the 2 dimensional array.
When above points are reflected to your script, it becomes as follows.
Modified script:
From:
var duplicate = false;
loop1:
for (var x = 0; x < entryVlArray.length; x++) {
loop2:
for (var j = 0; j < dbArray.length; j++) {
if (JSON.stringify(entryVlArray) == JSON.stringify(dbArray)) {
duplicate = true;
break loop1;
}
}
}
To:
var duplicate = false;
for (var x = 0; x < entryVlArray.length; x++) {
for (var j = 0; j < dbArray.length; j++) {
if (JSON.stringify(entryVlArray[x]) == JSON.stringify(dbArray[j])) {
duplicate = true;
break;
}
}
}
console.log(duplicate)
By this modification, when each element (1 dimensional array) in the 2 dimensional array is the same, duplicate becomes true.
Note:
As other method, when an object for searching each row value is prepared, I think that the process cost might be able to be reduced a little. In this case, the script is as follows. Please modify as follows.
From:
var duplicate = false;
loop1:
for (var x = 0; x < entryVlArray.length; x++) {
loop2:
for (var j = 0; j < dbArray.length; j++) {
if (JSON.stringify(entryVlArray) == JSON.stringify(dbArray)) {
duplicate = true;
break loop1;
}
}
}
To:
var obj = entryVlArray.reduce((o, e) => Object.assign(o, {[JSON.stringify(e)]: true}), {});
var duplicate = dbArray.some(e => obj[JSON.stringify(e)]);
References:
reduce()
some()
Added:
About your following 2nd question,
AMAZING!!!! Would there be a way of capturing these duplicates in a pop up, using reduce() and some()?
When you want to retrieve the duplicated rows, how about the following script? In this case, I thought that filter() is useful instead of some().
Modified script:
var obj = entryVlArray.reduce((o, e) => Object.assign(o, {[JSON.stringify(e)]: true}), {});
// var duplicate = dbArray.some(e => obj[JSON.stringify(e)]);
var duplicatedRows = dbArray.filter(e => obj[JSON.stringify(e)]);
console.log(duplicatedRows)
In this modified script, you can see the duplicated rows at the log.
About a pop up you expected, if you want to open a dialog including the duplicated rows, how about adding the following script after the line of var duplicatedRows = dbArray.filter(e => obj[JSON.stringify(e)]);?
Browser.msgBox(JSON.stringify(duplicatedRows));
I'm working from the solution provided HERE to compare two arrays. The example provided returns values found in both arrays to Array1 (same) and values only found on one or the other two Array2 (diff).
ISSUE: When I apply it to my own script, valuesDATA returns nothing and valuesCheckSeeding returns ALL values from both arrays
DESIRED RESULT: I have two arrays that I'd either like to create a third out of, or only select values from the first array, valuesDATA which are NOT present in the second, valuesCheckSeeding. Using the solution above, I was trying to have all values not found in valuesCheckSeeding AND valuesDATA pushed to valuesDATA.
SAMPLE OF valuesDATA: "U09 F
Harford FC Hill/Healey - A
MD
CMSA Girls Saturday U09 A/B North
Premier - Top
TID0118"
What am I doing wrong? I tinkered with changing matchfound==false and matchfound=true in the loop, but that still didn't give me the desired result.
MOST RELEVANT SNIPPET
var matchfound = false;
for (var i = 0; i < valuesDATA.length; i++) {
matchfound=false;
for (var j = 0; j < valuesCheckSeeding.length; j++) {
if (valuesDATA[i] == valuesCheckSeeding[j]) {
valuesCheckSeeding.splice(j, 1);
matchfound=true;
continue;
}
}
if (matchfound==false) {
valuesCheckSeeding.push(valuesDATA[i]);
valuesDATA.splice(i, 1);
i=i-1;
}
}
WORKIG SCRIPT EDITED FROM COMMENTS/ANSWERS BELOW
//UPDATE SEEDING SHEET
function updateSeedingSheet() {
var today = Utilities.formatDate(new Date(),Session.getScriptTimeZone(), "MM/dd/yyyy hh:mm a");
//INPUT SHEET INFO
var inputCurrentRow = 4;
var inputCurrentColumn = 20;
var inputNumRows = 1000;
var inputNumColumns =1;
var ssInput = SpreadsheetApp.openById('1Wzg2BklQb6sOZzeC0OEvQ7s7gIQ07sXygEtC0CSGOh4');
var sheetDATA = ssInput.getSheetByName('DATAREF');
var rangeDATA = sheetDATA.getRange(inputCurrentRow, inputCurrentColumn, inputNumRows, inputNumColumns);
var valuesDATA = rangeDATA.getValues();
//SEEDING SHEET INFO
var seedingCurrentRow = 4;
var seedingCurrentColumn = 1;
var seedingNumRows = 1000;
var seedingNumColumns = 1;
var ssSeeding = SpreadsheetApp.openById('1DuCHeZ3zba-nHq-7vYTrylncPGqcA1J9jNyW9DaS3mU');
var sheetSeeding = ssSeeding.getSheetByName('Seeding');
var rangeCheckSeeding = sheetSeeding.getRange(4, 102, 1000, 1);
var columnToClear = sheetSeeding.getRange(seedingCurrentRow, seedingCurrentColumn, seedingNumRows, seedingNumColumns);
var valuesCheckSeeding = rangeCheckSeeding.getValues();
//METHOD TO FILTER
valuesCheckSeeding = valuesCheckSeeding.map(function(e){return e[0];}); //flatten this array
var filteredArr = valuesDATA.filter(function(e){
return !(this.indexOf(e[0])+1);
},valuesCheckSeeding);
Logger.log(filteredArr);
Logger.log(filteredArr.length);
var rangeSeeding = sheetSeeding.getRange(seedingCurrentRow, seedingCurrentColumn, filteredArr.length, seedingNumColumns);
sheetSeeding.getRange('A1').setValue(today);
columnToClear.clearContent();
rangeSeeding.setValues(filteredArr);
/*
//ALTERNATIVE METHOD USING LOOPS
for (var i = 0; i < valuesDATA.length; i++) {
for (var j = 0; j < valuesCheckSeeding.length; j++) {
if (valuesDATA[i][0] == valuesCheckSeeding[j][0]) {
valuesDATA.splice(i, 1);
i--; //account for the splice
break; //go to next i iteration of loop
}
}
}
Logger.log("VALUES DATA:" + valuesDATA);
Logger.log("VALUES CHECK SEEDING: " + valuesCheckSeeding);
//sheetSeeding.getRange('A1').setValue(today);
//rangeSeeding.clearContent();
//rangeSeeding.setValues(valuesDATA); //INCORRECT RANGE HEIGHT, WAS 71 BUT SHOULD BE 1000 - Is splice affecting this?
*/
}//END FUNCTION
V8(ES2016 update):
You can use newer and efficient set class
const array1 = [[1],[2],[3]],
array2 = [[1],[3],[4]],
set = new Set(array2.flat())
console.info(array1.filter(e => !set.has(e[0])))
//expected output [[2]]
You're checking a 2D array. You'd need to use [i][0] and [j][0]
You can try only splicing valuesDATA
Try
for (var i = 0; i < valuesDATA.length; i++) {
for (var j = 0; j < valuesCheckSeeding.length; j++) {
if (valuesDATA[i][0] == valuesCheckSeeding[j][0]) {
valuesDATA.splice(i, 1);
i--; //account for the splice
break; //go to next i iteration of loop
}
}
}
Logger.log(valuesDATA);
Alternatively, try
valuesCheckSeeding = valuesCheckSeeding.map(function(e){return e[0];}); //flatten this array
var filteredArr = valuesDATA.filter(function(e){
return !(this.indexOf(e[0])+1);
},valuesCheckSeeding);
Logger.log(filteredArr);
I am confused about how to iterate on multiple values.
for example : values.categories[0].num[0].entry[0].label;
Do I need to write three for loops in order to iterate through categories, num and entry.
Because categories[0] will always identify the 1st position, but am looking for generic categories[i].
Can you please help me out whether to write three for loops or better option is there to achieve.?
This is what I have tried:
var result = [];
for (var i = 0; i < categories.length; i++) {
var abc = categories[i].num;
for (var j = 0; j < abc.length; j++){
var def = num[i].entry;
}
for(var k = 0; k < def.length; k++){
var ghi = entry[i].label;
result.push(ghi)
console.log(result);
}
}
you can use the each function of jquery.
$.each(categories, function(ci, num) {
// This set the index of the array in ci and the value in num = categories[ci]
$.each(num, function(ni, entry) {
// etc ...
});
});
if you want it to stop the iteration you can return false inside the callback function.
Hello there am trying to save news tweets into three different array which are dynamically created.
am finding trouble when i want to get the text from each one of those array and make another request to twitter.
news_tweets("reuters","1652541",3);
function news_tweets(query, user_id,count) {
news_array = [];
$.getJSON("https://api.twitter.com/1/statuses/user_timeline.json?include_entities=true&include_rts=false&user_id=" + user_id + "&count="+count+
"&callback=?",
function (data) {
for (var i = 0; i < count; i++) {
var user = data[i].user.name;
var date = data[i].created_at;
var profile_img = data[i].user.profile_image_url;
var text = data[i].text;
var url = (data[i].entities.urls.length > 0 ? data[i].entities.urls[0].url : '');
news_array[i] = [{user:user,date:date,profile_img:profile_img,text:text,url:url}];
}
for (var i = 0; i < news_array.length; i++) {
for (var x=0; x<i.length; x++){
console.log(news_array[i][x].user);
}
}
});
}
It doesn't show anything on the console.log.
thanks for the help!!!!!
First, make sure that your count is smaller than the data array's length, otherwise this could lead to some undefined values:
for (var i = 0; i < count && i < data.length; i++) …
Then, why are you creating all those one-element-arrays in the news_array? Just use only objects.
This would solve your actual issue: You are looping wrong over those inner arrays. The correct code would be
for (var i = 0; i < news_array.length; i++) {
for (var x = 0; x < news_array[i].length; x++){
console.log(news_array[i][x].user);
}
}
Also, you should indent your code properly. You have some odd braces around, which don't make the code readable.
The problem is the x<i.length in the for loop near the end. i is a number, so it doesn't have a length. You probably meant x < news_array[i].length.
You may try the following:
Use the push method to append elements / data in your array new_array
Use only 1 loop for to display the user value on console
So your code will be something like this:
news_tweets("reuters","1652541",3);
function news_tweets(query, user_id,count) {
news_array = [];
$.getJSON("https://api.twitter.com/1/statuses/user_timeline.json?include_entities=true&include_rts=false&user_id=" + user_id + "&count="+count+
"&callback=?",
function (data) {
for (var i = 0; i < count; i++) {
var user = data[i].user.name;
var date = data[i].created_at;
var profile_img = data[i].user.profile_image_url;
var text = data[i].text;
var url = (data[i].entities.urls.length > 0 ? data[i].entities.urls[0].url : '');
// Pushing your elements in your array, 1 by 1
news_array.push({user:user,date:date,profile_img:profile_img,text:text,url:url});
}
// Here you only need 1 loop!
for (var i = 0; i < news_array.length; i++) {
console.log(news_array[i][x].user);
}
});
}
First thing is i would loop the first one till data.length rather than count because its an api and it "might" or "might not" return all the data. So it will be fool proof to loop till data.length
And your problem is with i.length
for (var i = 0; i < news_array.length; i++) {
console.log(news_array[i].user);
}
this should work. not sure why you had to loop through a loop.
function split(str)
{
var array = str.split(';');
var test[][] = new Array();
for(var i = 0; i < array.length; i++)
{
var arr = array[i].split(',');
for(var j = 0; j < arr.length; j++)
{
test[i][j]=arr[j];
}
}
}
onchange="split('1,2,3;4,5,6;7,8,9;a,b,c;d,e,f;g,h,i')"
it was not working. i need to split this string to 6*3 multi dimentional array
var array[][] = new Array() is not valid syntax for declaring arrays. Javascript arrays are one dimensional leaving you to nest them. Which means you need to insert a new array into each slot yourself before you can start appending to it.
Like this: http://jsfiddle.net/Squeegy/ShWGB/
function split(str) {
var lines = str.split(';');
var test = [];
for(var i = 0; i < lines.length; i++) {
if (typeof test[i] === 'undefined') {
test[i] = [];
}
var line = lines[i].split(',');
for(var j = 0; j < line.length; j++) {
test[i][j] = line[j];
}
}
return test;
}
console.log(split('a,b,c;d,e,f'));
var test[][] is an invalid javascript syntax.
To create a 2D array, which is an array of array, just declare your array and push arrays into it.
Something like this:
var myArr = new Array(10);
for (var i = 0; i < 10; i++) {
myArr[i] = new Array(20);
}
I'll let you apply this to your problem. Also, I don't like the name of your function, try to use something different from the standards, to avoid confusion when you read your code days or months from now.
function split(str)
{
var array = str.split(';'),
length = array.length;
for (var i = 0; i < length; i++) array[i] = array[i].split(',');
return array;
}
Here's the fiddle: http://jsfiddle.net/AbXNk/
var str='1,2,3;4,5,6;7,8,9;a,b,c;d,e,f;g,h,i';
var arr=str.split(";");
for(var i=0;i<arr.length;i++)arr[i]=arr[i].split(",");
Now arr is an array with 6 elements and each element contain array with 3 elements.
Accessing element:
alert(arr[4][2]); // letter "f" displayed