Advice on the best way to collect values in an array - javascript

I need to save all the color values ​​of the elements in the pages of my site and put them in a database. I thought I'd do it this way:
First thing I'm going to pick up the rgb values ​​of each element so
$("*").each(function(e){
createColorArray($(this).css('backgroundColor'));
});
then in the function createColorArray store into an array all the values ​​that are passed
function createColorArray(rgbColor)
{
//Create rgb array
}
and finally remove duplicate items from my array
function removeDoupe(ar) {
var temp = {};
for (var i = 0; i < ar.length; i++)
temp[ar[i]] = true;
var r = [];
for (var k in temp)
r.push(k);
return r;
}
now my question is,
how recommended to create the array? directly inside the $ ("*") or in a dedicated function as I'm thinking? also i need than once removed duplicates in the new array "clean" as well as the rgb value I would have also given the number of times that value was in the original.
Some example code?

As I mentioned in the comments, why not check for duplicates earlier? A simple example:
var colors = [];
$('*').each(function(i, el){
var $element = $(el),
color = $element.css('background-color');
if(!~$.inArray(color, colors))
colors.push(color);
});
console.log(colors);
http://jsfiddle.net/sL9oeywk/

The best way to do this is to do it all while you are working on it. Heres a way you could potentially do it:
var colors = new Array();
var tempColors = {};
$(".colors").each(function(){
var c = $(this).val();
// check if the color exists without looping
if(typeof tempColors[c] == "undefined"){
// if it doesn't, add it to both variables.
tempColors[c] = true;
colors.push(c);
}
});
This will result in two variables: one is an object that you don't have to loop through to find out if you defined it before, one is a colors array that you push to using standard javascript.
You shouldn't make it a dedicated function if you are not reusing it, but you could make it an object like this:
var colors = function(){
var self = this;
self.array = new Array();
// this is a dedicated check function so we don't need separate variables.
// returns true if the color exists, false otherwise
self.check = function(color){
for(var i =0; i < self.array.length; i++){
if(self.array[i] === color) return true;
}
return false;
}
self.add = function(color){
// use the check function, if it returns false, the color does not exist yet.
if(!self.check(color)){
self.array.push(c);
}
}
}
You can then instantiate a colorlist using var colorlist = new colors(); and add colors using colorlist.add("dd0300"). Accessing the array can be done by requesting colorlist.array.

Related

converting JS array with objects to HTML collection

I got to the point with my project where I decided to simplify some of the js functions where I am looking for a parent in a DOM tree, then drill down to the elements many many times in one function. instead I though I will make instances of a function which will keep some data so then I can refer and operate on objects in easy way. I got it working but as I was going along, I decided to extend functionality and add some extra functions like getElementsByClassNameThenTagName.
I loop through the arrays and if add matching elements to the array.
I have noticed (sadly only now) that I am creating an array with elements rather than HTML collection. As a results, I cannot refer to the objects in my findings by typing buttons['reset'].disabled = false;. I can access my reset button by buttons[3].disabled = false; but this would cause a lot of inconvenience.
I am therefore looking for a way to convert my array with object into a HTML collection.
Please see below my current function:
this.getElementsByClassNameThenTagName = function (elementClass, elementTag) {
if (parentNode == null) {
this.init();
}
var results = [];
var regexStr = elementClass;
var regex = new RegExp(regexStr);
var x = moduleNode.getElementsByClassName(elementClass);
// console.log(x);
var y;
for ( var i = 0; i < x.length; i++ ) {
// console.log(i);
y = x[i].getElementsByTagName(elementTag);
// console.log(y);
for (var k=0; k<y.length; k++){
// console.log(y[k]);
results.push(y[k]);
}
// console.log(results);
}
return results;
};
Any suggestions please?
Thanks.
this.getElementsByClassNameThenTagName = function (elementClass, elementTag) {
if (parentNode == null) {
this.init();
}
var results = {}; // thid should be an object (collection)
var x = moduleNode.querySelectorAll("." + elementClass + " " + elementTag);
x.forEach(function(y) {
var name = y.getAttribute("name"); // if you really sure that all the matched elements have names
results[name] = y;
});
return results;
};
Now you can use the results array like this:
var someElement = results['some name'];
NOTE: All the matched elements x should have a name attribute, and all the name attributes of the matched elements should be unique.

Get array from dynamic variable

I'm sure this is really simple, I just can't work out how to do it.
I want to dynamically make an array from one variable equal to another:
var pageID = document.getElementsByClassName('page_example')[0].id;
Let's say this returned an id of page_1
var page_1 = ['value1','value2','value3'];
var page_2 = ['value4','value5','value6'];
var page_3 = ['value7','value8','value9'];
var page_array = (then have the associated pageID's array here)
So in this example,
page_array would equal ['value1','value2','value3']
Instead of storing the array in separate variables, store them in an object with the ids as the key:
var pages = {
page_1: ['value1','value2','value3'],
page_2: ['value4','value5','value6'],
page_3: ['value7','value8','value9']
}
You can access the arrays as though the object was an assosiative array:
var pageID = "page_1";
var pageArray = pages[pageID];
Depending on what you would like to achieve, you can one of two or three methods.
What I consider the easiest method is an if/else statement:
if (condition) {
page_array = page_1.slice(0);
} else if (other condition) {
page_array = page_2.slice(0);
} else if...
Another method you can use, again depending on what your ultimate goal is, would be a for loop:
for (var i = 0; i < numOfDesiredLoops; i++) {
page_array = page_1.slice(0, i);
}
Or you could use a combination of both:
for (var i = 0; i < numOfDesiredLoops; i++) {
if (condition) {
page_array = page_1.slice(0);
} else if (other condition) {
page_array = page_2.slice(1);
} else if...
}
With more information on why you need this variable to change, I can give you a better answer.
edit: keep in mind the arguments of .slice() can be whatever you want.

cannot iterate through array and change value in JS

I have to iterate through an array, change one of its values, and create another array refelecting the changes.
this is what I have so far:
JS:
var arr = new Array();
arr['t1'] = "sdfsdf";
arr['t2'] = "sdfsdf";
arr['t3'] = "sdfsdf";
arr['t4'] = "sdfsdf";
arr['t5'] = "sdfsdf";
var last = new Array();
for (var i = 0; i <= 5; i++) {
arr['t2'] = i;
last.push(arr);
}
console.log(last);
Unfortunately, these are my results
As you can see, I am not getting the results needed as 0,1,2.. instead I am getting 2, 2, 2..
This is what i would like my results to be:
How can I fix this?
You have to make a copy, otherwise you are dealing with reference to the same object all the time. As it was said before - javascript does not have associate arrays, only objects with properties.
var arr = {}; // empty object
arr['t1'] = "sdfsdf";
arr['t2'] = "sdfsdf";
arr['t3'] = "sdfsdf";
arr['t4'] = "sdfsdf";
arr['t5'] = "sdfsdf";
var last = new Array();
for (var i = 0; i <= 5; i++) {
var copy = JSON.parse(JSON.stringify(arr)); //create a copy, one of the ways
copy['t2'] = i; // set value of its element
last.push(copy); // push copy into last
}
console.log(last);
ps: you can use dot notation arr.t1 instead of arr['t1']
The array access with ['t2'] is not the problem. This is a regular JavaScript feature.
The problem is: You are adding the SAME array to "last" (5 times in code, 3 times in the screenshot).
Every time you set ['t2'] = i, you will change the values in "last" also, because they are actually just references to the same array-instance.
You must create a copy/clone of the array before you add it to "last".
This is what will happen in all languages where arrays are references to objects (Java, C#...). It would work with C++ STL though.

JavaScript empty array

https://stackoverflow.com/a/1234337/1690081
shows that array.length = 0;will empty array but in my code it doesn't
here's an sample:
window.onload = draw;
window.onload = getFiles;
var namelist = [];
function draw(){
// assing our canvas to element to a variable
var canvas = document.getElementById("canvas1");
// create html5 context object to enable draw methods
var ctx = canvas.getContext('2d');
var x = 10; // picture start cordinate
var y = 10; // -------||---------
var buffer = 10; // space between pictures
for (i=0; i<namelist.length; i++){
console.log(namelist[i])
var image = document.createElement('img');
image.src = namelist[i];
canvas.appendChild(image);
ctx.drawImage(image,x,y,50,50);
x+=50+buffer;
}
}
function getFiles(){
namelist.length = 0;// empty name list
var picturesFiles = document.getElementById('pictures')
picturesFiles.addEventListener('change', function(event){
var files = picturesFiles.files;
for (i=0; i< files.length; i++){
namelist.push(files[i].name);
console.log(namelist)
}
draw();
}, false);
}
after i call getFiles() second time. It doesn't remove the previous list, just appends to it. any idea why?
You should empty the array in the event handler, not getFiles which is only called once per pageload. It is actually doing nothing because the array is already empty when the page loads.
picturesFiles.addEventListener('change', function(event){
namelist.length = 0; //empty it here
var files = picturesFiles.files;
for (i=0; i< files.length; i++){
namelist.push(files[i].name);
console.log(namelist)
}
draw();
}, false);
Another problem is that you cannot just set .src to the name of a file. That would make the request to your server for the file.
To really fix this, just push the file objects to the namelist:
namelist.push(files[i]);
Then as you process them in draw, create localized BLOB urls to show them:
var file = namelist[i];
var url = (window.URL || window.webkitURL).createObjectURL( file );
image.src = url;
It looks like you're using namelist as a global variable. This would be easier (and would avoid needing to empty it at all) if you passed the new array out of the function as a return value.
ie:
function getFiles() {
var newNameList = [];
..... //push entries here.
return newNameList;
}
... and then populate namelist from the return value where you call it:
namelist = getFiles();
However, to answer the question that was actually asked:
Instead of setting the length to zero, you can also reset an array simply by setting it to a new array:
namelist = [];
You haven't shown us how you're 'pushing' entries to the list, but I suspect that the end result is that namelist is being generated as a generic object rather than an array object. If this is the case, then setting .length=0 will simply add a property to the object named length with a value of 0. The length property in the way you're using it only applies to Array objects.
Hope that helps.
If you are using non-numeric indexes then the array will not clear.
"...whenever the length property is changed, every property whose name is an array index whose value is not smaller than the new length is automatically deleted"
Test:
var arr = [];
arr['this'] = 'that';
arr.length = 0;
console.log(arr);
//output ['this':'that']
var arr = [];
arr[0] = 'that';
arr.length = 0;
console.log(arr);
//output []
There is nothing wrong with how you empty the array, so there has to be something else that is wrong with your code.
This works fine, the array doesn't contain the previous items the second time:
var namelist = [];
function draw() {
alert(namelist.join(', '));
}
function getFiles() {
namelist.length = 0; // empty name list
namelist.push('asdf');
namelist.push('qwerty');
namelist.push('123');
draw();
}
getFiles();
getFiles();
Demo: http://jsfiddle.net/Guffa/76RuX/
Edit:
Seeing your actual code, the problem comes from the use of a callback method to populate the array. Every time that you call the function, you will add another event handler, so after you have called the function the seccond time, it will call two event handlers that will each add all the items to the array.
Only add the event handler once.

fastest way to loop through an array

I want to return an array when one of the elements matches an item within an array.
Is the below code the fastest way to loop through an array when a value matches in a javascript array of arrays?
Note : Welcome any suggestions to modify the variable relatedVideosArray to make it a different data structure for better performance.
var relatedVideosArray = [
["1047694110001"],
["1047694111001", "1019385098001","1020367665001","1020367662001", "1019385097001", "1020367667001"],
["1040885813001"],
["1019385094001", "1019385096001"],
["952541791001", "952544511001", "952544512001", "952544508001", "952541790001","952580933001", "952580934001", "1051906367001"]
]
function getRelatedVideos(videoClicked){
var tempStoreArray = [];
var getCurrentId = videoClicked;
var relVideoslen = relatedVideosArray.length;
for(var i in relatedVideosArray) {
tempStoreArray = relatedVideosArray[i];
for(var j in tempStoreArray){
if(tempStoreArray[j] == getCurrentId){
return relatedVideosArray[i];
}
}
}
}
Update: I initially thought of making a key of video ids and values as all the related ids, but I want to display the key as well as all the related ids if any of the ids within the value array are clicked. Hope this helps to explain the constraint I have.
Modern day browsers support Array indexOf.
For the people saying the array indexOf is slower, basic tests on speed.
var values = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20];
console.time("for");
for(var i=0;i<1000;i++){
for(var j=0;j<=values.length;j++){
if(values[j]===20) break;
}
}
console.timeEnd("for");
console.time("reverse for");
for(i=0;i<1000;i++){
for(var j=values.length-1;j>=0;j--){
if(values[j]===1) break;
}
}
console.timeEnd("reverse for");
console.time("while");
for(i=0;i<1000;i++){
var j=0;
while (j<values.length){
if(values[j]===20) break;
j++;
}
}
console.timeEnd("while");
console.time("reverse while");
for(i=0;i<1000;i++){
var j=values.length-1;
while (j>=0){
if(values[j]===1) break;
j--;
}
}
console.timeEnd("reverse while");
console.time("indexOf");
for(var i=0;i<1000;i++){
var x = values.indexOf(20);
}
console.timeEnd("indexOf");
console.time("toString reg exp");
for(var i=0;i<1000;i++){
var x = (/(,|^)20(,|$)/).test(values.toString);
}
console.timeEnd("toString reg exp");
Two possible solutions:
var relatedVideosArray = [
["1047694110001"],
["1047694111001", "1019385098001","1020367665001","1020367662001", "1019385097001", "1020367667001"],
["1040885813001"],
["1019385094001", "1019385096001"],
["952541791001", "952544511001", "952544512001", "952544508001", "952541790001","952580933001", "952580934001", "1051906367001"]
]
//var getCurrentId = "1019385098001";
var getCurrentId = "1040885813001";
console.time("indexOf");
var tempStoreArray = [];
for(var i = relatedVideosArray.length-1; i>=0; i--){
var subArr = relatedVideosArray[i];
if(subArr.indexOf(getCurrentId)!==-1){
tempStoreArray.push(subArr);
}
}
console.timeEnd("indexOf");
console.log(tempStoreArray);
console.time("toString reg exp");
var tempStoreArray = [];
var re = new RegExp("(,|^)" + getCurrentId + "(,|$)");
for(var i = relatedVideosArray.length-1; i>=0; i--){
var subArr = relatedVideosArray[i];
if(re.test(subArr.toString())){
tempStoreArray.push(subArr);
}
}
console.timeEnd("toString reg exp");
console.log(tempStoreArray);
I believe so if you keep your current structure. Unless you have a way of 'flattening' the array first, so that rather than being nested, there is simply one array with all the values. If this is out of your control or impractical, then you have no other choice than to iterate over every element and its elements.
Otherwise, would you be able to add the values to a map? The current video id would be the key, and the value would be the list of related videos.
If you have control over the data structure then I highly recommend changing it to something more amenable to the type of searches you are performing. First thing that comes to mind is an array of associative arrays. Each of your video arrays would be keyed with the video id ( set the value to anything you want ). That would make your search O(n), where n = the total number of video lists you have.
I'll post some code for this when I get in front of the computer.

Categories