Related
I am facing an issue when populating an array of the object dynamically in javascript. I have this sample data as below:
I have to populate following arrays with the data from above:
c1_Arr = [];
c2_Arr = [];
var torontoObj = { arName: 'تورونتو', enName: 'Totonto', value: 0 };
var parisObj = { arName: 'باريس', enName: 'Paris', value: 0 };
var londonObj = { arName: 'لندن', enName: 'London', value: 0 };
Now I am looping through the data to set the values from data as:
var resultCount = results.features.length;
for (var i = 0; i < resultCount; i++) {
var data = results.features[i].attributes;
parisObj.value = data.Paris;
londonObj.value = data.London;
torontoObj.value = data.Toronto;
if (data.Ind_ID === 101) {
c1_Arr.push(parisObj);
c1_Arr.push(londonObj);
c1_Arr.push(torontoObj);
}
}
console.log(c1_Arr);
I am getting this data in console:
Here I am getting the values of the object i.e. Ind_ID = 102 instead of the object values of Ind_ID = 101 (first object).
How to get the values of the required object using the Ind_ID?
The problem is because even though you have the if condition there but you are updating the value of the objects in the loop and since you have already pushed them objects you still have the reference in the main objects. They get overwritten.
Create the 3 objects (torontoObj, etc.) inside the loop.
Reference is getting updated in the second iteration (where Ind_ID is 102)
You should rather do
var resultCount = results.features.length;
for (var i = 0; i < resultCount; i++) {
var data = results.features[i].attributes;
if (data.Ind_ID === 101) {
parisObj.value = data.Paris;
londonObj.value = data.London;
torontoObj.value = data.Toronto;
c1_Arr.push(parisObj);
c1_Arr.push(londonObj);
c1_Arr.push(torontoObj);
}
}
console.log(c1_Arr);
Your object values are getting updated even after being set inside the if loop, simply because, you're not limiting it from being updated.
You could probably do one of the following 2 things:
The simpler one:
Extract the values of Paris, London and Toronto fields of data only if the Ind
_ID is 101.
like this:
var resultCount = results.features.length;
for (var i = 0; i < resultCount; i++) {
var data = results.features[i].attributes;
if (data.Ind_ID === 101) {
parisObj.value = data.Paris;
londonObj.value = data.London;
torontoObj.value = data.Toronto;
c1_Arr.push(parisObj);
c1_Arr.push(londonObj);
c1_Arr.push(torontoObj);
}
}
console.log(c1_Arr);
The more elegant one:
Extract the array element which only matches your condition, in other words filter.
var resultCount = results.features.length;
var data = results.features.filter(feature => feature.attributes.Ind_ID === 101);
parisObj.value = data[0].Paris;
londonObj.value = data[0].London;
torontoObj.value = data[0].Toronto;
console.log(c1_Arr);
I have two arrays:
var arr1 = [1,2,3,4,5]
var arr2 = [7,1,8,2,12,3,4,28,5]
I need to go through arr2 looking for matches to arr1, but it has to be in order (1,2,3,4,5). As you can see in arr2, the order does exists, but there are some numbers in between.
[7,1,8,2,12,3,4,28,5]
I have about 50 arrays similar to arr2, so I need to look through each one, and when I find a match, push it out to a "results" object. Small issue though is that some arrays will not have the entire match, may only have 1,2,3 or any variation of the search. Also, if the array I'm searching in is NOT in order, (IE: starts at 2,3,4) skip over it entirely.
The idea is to loop through these arrays, and when I find a match, add a count to the results array.
For example, using arr1 as the search, go through these arrays:
[7,1,8,2,12,3,4,28,5],
[7,1,8,2,12,3,4],
[7,8,1,2],
[1,2,3]
and have a result that looks like this (a dictionary of what was searched for, and a count of what was found) :
{1:4, 2:4, 3:3, 4:2, 5:1}
I tried doing a bunch of for-loops, but I can't figure out how to skip over a number that I'm not looking for, and continue onto the next iteration, while saving the results into a dictionary object.
let list = [[7,1,8,2,12,3,4,28,5], [7,1,8,2,12,3,4], [7,8,1,2], [1,2,3]];
let search = [1, 2, 3, 4, 5];
// Initialize result with zeros:
let result = search.reduce((result, next) => {
result[next] = 0;
return result;
}, {});
// Increment result for items found:
list.forEach(array => {
for (let i = 0, j = 0; i < array.length && j < search.length; ++i) {
if (array[i] == search[j]) {
++result[search[j]];
++j;
}
}
});
console.log(result);
Essentially this:
var needle = [1,2,3,4,5]
var collection = [[7,1,8,2,12,3,4,28,5], [7,1,8,2,12,3,4], [7,8,1,2], [1,2,3]]
// start with an object
var results = {}
// populate object with zeros
needle.forEach(function (i) { results[i] = 0 })
// define an index to iterate through collection
var i = 0
// define an index to conditionally iterate through "arr1"
var j = 0
// define an index to iterate through collection arrays
var k = 0
// define surrogate for the arrays in the collection
var arr
while (i < collection.length) {
// get collection array
arr = collection[i]
// reset the indices
j = 0
k = 0
while (k < arr.length) {
// if same element on needle is in a collection array
if (needle[j] === arr[k]) {
// save it in an object starting at 1
results[needle[j]]++
j++ // increment needle
}
k++ // increment array in collection
}
i++ // increment collection
}
console.log(results) // {1:4, 2:4, 3:3, 4:2, 5:1}
I hope that helps!
var arr1 = [1,2,3,4,5];
var arr2 = [7,1,8,2,12,3,4,28,5];
function givenTwoArrays(a,b, obj){
var obj = obj || {};
var cond = true;
function otherMatch(indexFound,elementFound){
var indexOnA = a.indexOf(elementFound);
return a.some(function(ele, idx){
if(idx > indexOnA)
return b.some(function(bele,bidx){
return ele == bele && bidx < indexFound;
});
});
}
a.map(function(aele,idx){
if(cond){
var indexFound = b.findIndex(function(bele){
return aele == bele;
});
if(typeof indexFound !== 'undefined'){
if(!otherMatch(indexFound,aele)){
if(typeof obj[aele] !== 'undefined')
obj[aele]++;
else{
obj[aele] = 1;
}
} else {
cond = false;
}
}else
cond = false;
}
});
return obj;
}
console.log("first pass");
console.log(givenTwoArrays(arr1,arr2))
console.log("second pass");
console.log(givenTwoArrays(arr1,arr2,{
"1": 1,
"2": 1,
"3": 1,
"4": 1,
"5": 1
}));
I think this will work, just need to add a little recursion!
var orign = [1,2,3,4,5];
var arr = [[7,1,8,2,12,3,4,28,5], [7,1,8,2,12,3,4], [7,8,1,2], [1,2,3]];
//temp result
var arrTmp = [];
for (var x in arr){
var match = 0;
var mis = 1;
var curIndex = 0;
var cur = orign[curIndex];
var arrTmpX = [];
for(var y in arr[x]){
if(arr[x][y] !== cur){
mis=1;
}else{
//add match after mismatch
arrTmpX.push(cur);
curIndex++
cur = orign[curIndex];
}
}
arrTmp.push(arrTmpX);
}
//calc result
var result = {};
for (var x in orign){
result[orign[x]] = 0;
for(var y in arrTmp){
if(arrTmp[y].length>x)result[orign[x]]++;
}
}
console.log(result);
this works
I have an element structured like this:
Element ->
[{values: arrayOfObject, key:'name1'}, ... ,{values: arrayOfObjectN, key:'nameN'}]
arrayDiObject -> [Object1, Object2, ... , ObjectN] //N = number of lines in my CSV
Object1 -> {x,y}
I have to take data from a big string:
cityX#substanceX#cityY#substanceY#
I thought to make it this way, but it seems like it pushes always in the same array of objects. If I put oggetto = {values: arrayDateValue, key: key}; inside the d3.csv function, instead if I put outside the function it add me only empty objects.
Here is my code:
var final = new Array();
var oggetto;
var key;
function creaDati() {
var newdate;
var arrayDateValue = new Array();
var selString = aggiungiElemento().split("#");
//selString is an array with selString[0]: city, selString[1]: substance and so on..
var citySelected = "";
var substanceSelected = "";
for (var i = 0; i < selString.length - 1; i++) {
if (i % 2 === 0) {
citySelected = selString[i];
} else if (i % 2 !== 0) {
substanceSelected = selString[i];
key = citySelected + "#" + substanceSelected;
d3.csv("/CSV/" + citySelected + ".csv", function(error, dataset) {
dataset.forEach(function(d) {
arrayDateValue.push({
x: d.newdate,
y: d[substanceSelected]
});
});
});
oggetto = {
values: arrayDateValue,
key: key
};
arrayDateValue = [];
final.push(oggetto);
}
}
}
Any idea ?
First you should make the if statement for the city and then for the key, which you seem to be doing wrong since you want the pair indexes to be the keys and the not pair to be the city, and you are doing the opposite. And then you need to have the d3.csv and push the objects outside of the if statement, otherwise in your case you are just adding elements with citySelected="".
Try something like :
for(var i = 0; i < selString.length -1; i+=2){
cittySelected = selString[i];
substanceSelected = selString[i+1];
key = citySelected + "#" + substanceSelected;
d3.csv("/CSV/"+citySelected+".csv", function(error, dataset){
dataset.forEach(function(d){
arrayDateValue.push({x: d.newdate, y: d[substanceSelected]});
});
});
oggetto = {values: arrayDateValue, key: key};
arrayDateValue = [];
final.push(oggetto);
}
It's is not the best way to do it, but it is clearer that what you are following, i think.
In the if(i % 2 == 0) { citySelected = ... } and else if(i % 2 !== 0) { substanceSelected = ... } citySelected and substanceSelected will never come together.
The values should be in one statement:
if(...) { citySelected = ...; substanceSelected = ...; }
The string can be splitted into pairs
city1#substance1, city2#substance2, ...
with a regex (\w{1,}#\w{1,}#).
Empty the arrayDateValue after the if-statement.
Hint:
var str = "cityX#substanceX#cityY#substanceY#";
function createArr(str) {
var obj = {};
var result = [];
var key = "";
// '', cityX#substanceX, '', cityYsubstanceY
var pairs = str.split(/(\w{1,}#\w{1,}#)/g);
for (var i = 0; i < pairs.length; i++) {
if(i % 2 !== 0) {
key = pairs[i];
// d3 stuff to create values
obj = {
// Values created with d3 placeholder
values: [{x: "x", y: "y"}],
// Pair
key: key
};
result.push(obj);
}
// Here should be values = [];
}
return result;
}
var r = createArr(str);
console.log(r);
May be you can do like this;
var str = "cityX#substanceX#cityY#substanceY",
arr = str.split("#").reduce((p,c,i,a) => i%2 === 0 ? p.concat({city:c, key:a[i+1]}) : p,[]);
console.log(JSON.stringify(arr));
RESOLVED-
The problem is about d3.csv which is a asynchronous function, it add in the array when it finish to run all the other code.
I make an XMLHttpRequest for each csv file and it works.
Hope it helps.
sorry, i m a beginner in javascript.
Can someone explain me how to modify this Object
{toto:[12,13,15],titi:[45,12,34]}
to this Array
newArray = [
{
toto:12,
titi:45
},{
toto:13,
titi:12
},{
toto:15,
titi:34}
]
Also, what the solution if the toto and titi doesn't have the same lenght
Thanks for support!
Here's how I did it. In this way, you don't need to know the names of the keys or the size of the array, but it does require a few loops.
obj = {toto:[12,13,15],titi:[45,12,34]};
newArray = [];
// Find the longest array in your data set
longest = 0;
Object.keys(obj).forEach(function(key) {
if (obj[key].length > longest) {
longest = obj[key].length;
}
});
// Loop through the existing data set to create new objects
for (i = 0; i<longest; i++) {
newObject = {};
Object.keys(obj).forEach(function(key) {
newObject[key] = obj[key][i];
});
newArray.push(newObject);
}
console.log(newArray);
plnkr.co demo in the script.js file.
If you want to ignore keys that would have undefined values for uneven loops, you can add a conditional inside the forEach loop that creates a new object:
Object.keys(obj).forEach(function(key) {
if (obj[key][i] !== undefined) {
newObject[key] = obj[key][i];
}
});
Assuming lengths of toto and titi are the same:
Obj = {toto:[12,13,15],titi:[45,12,34]};
newArray = [];
for (var k in Obj["toto"]) {
newArray.push({ toto:Obj["toto"][k],titi:Obj["titi"][k] });
}
Since the lengths of your inner arrays are equal, you should be able to simply loop through them and add a value from each array (for each iteration) into a new array :
// Your input
var input = {toto:[12,13,15],titi:[45,12,34]};
// An array to store your output
var output = [];
// Since your inner arrays are of equal size, you can loop through them
// as follows
for(var i = 0; i < input.toto.length; i++){
output.push({ toto: input.toto[i], titi: input.titi[i]});
}
You can see a working example of this here and what the output array looks like below :
A more generic approach
var object = { toto: [12, 13, 15], titi: [45, 12, 34] },
newArray = function (o) {
var keys = Object.keys(o),
l = keys.reduce(function (r, a) { return Math.max(r, o[a].length); }, 0),
i = 0,
t,
result = [];
while (i < l) {
t = {};
keys.forEach(function (k) { t[k] = o[k][i]; });
result.push(t);
i++;
}
return result;
}(object);
document.write('<pre>' + JSON.stringify(newArray, 0, 4) + '</pre>');
I need to know if one or more duplicates exist in a list. Is there a way to do this without travelling through the list more than once?
Thanks guys for the suggestions. I ended up using this because it was the simplest to implement:
var names = [];
var namesLen = names.length;
for (i=0; i<namesLen; i++) {
for (x=0; x<namesLen; x++) {
if (names[i] === names[x] && (i !== x)) {alert('dupe')}
}
}
Well the usual way to do that would be to put each item in a hashmap dictionary and you could check if it was already inserted. If your list is of objects they you would have to create your own hash function on the object as you would know what makes each one unique. Check out the answer to this question.
JavaScript Hashmap Equivalent
This method uses an object as a lookup table to keep track of how many and which dups were found. It then returns an object with each dup and the dup count.
function findDups(list) {
var uniques = {}, val;
var dups = {};
for (var i = 0, len = list.length; i < len; i++) {
val = list[i];
if (val in uniques) {
uniques[val]++;
dups[val] = uniques[val];
} else {
uniques[val] = 1;
}
}
return(dups);
}
var data = [1,2,3,4,5,2,3,2,6,8,9,9];
findDups(data); // returns {2: 3, 3: 2, 9: 2}
var data2 = [1,2,3,4,5,6,7,8,9];
findDups(data2); // returns {}
var data3 = [1,1,1,1,1,2,3,4];
findDups(data3); // returns {1: 5}
Since we now have ES6 available with the built-in Map object, here's a version of findDups() that uses the Map object:
function findDups(list) {
const uniques = new Set(); // set of items found
const dups = new Map(); // count of items that have dups
for (let val of list) {
if (uniques.has(val)) {
let cnt = dups.get(val) || 1;
dups.set(val, ++cnt);
} else {
uniques.add(val);
}
}
return dups;
}
var data = [1,2,3,4,5,2,3,2,6,8,9,9];
log(findDups(data)); // returns {2 => 3, 3 => 2, 9 => 2}
var data2 = [1,2,3,4,5,6,7,8,9];
log(findDups(data2)); // returns empty map
var data3 = [1,1,1,1,1,2,3,4];
log(findDups(data3)); // returns {1 => 5}
// display resulting Map object (only used for debugging display in snippet)
function log(map) {
let output = [];
for (let [key, value] of map) {
output.push(key + " => " + value);
}
let div = document.createElement("div");
div.innerHTML = "{" + output.join(", ") + "}";
document.body.appendChild(div);
}
If your strings are in an array (A) you can use A.some-
it will return true and quit as soon as it finds a duplicate,
or return false if it has checked them all without any duplicates.
has_duplicates= A.some(function(itm){
return A.indexOf(itm)===A.lastIndexOf(itm);
});
If your list was just words or phrases, you could put them into an associative array.
var list=new Array("foo", "bar", "foobar", "foo", "bar");
var newlist= new Array();
for(i in list){
if(newlist[list[i]])
newlist[list[i]]++;
else
newlist[list[i]]=1;
}
Your final array should look like this:
"foo"=>2, "bar"=>2, "foobar"=>1