how to parse array and create new array with parsed values? - javascript

I have an array
var data = new Array("1111_3", "1231_54", "1143_76", "1758_12");
now I want to parse data[0] to get 1111.
var ids = new Array();
// example: ids = Array("1111", "1231", "1143", "1758");
and copy all ids from data to ids Array.
is it possible to do it like in php or do i need to use loops?
Thanks.

Really simple:
var ids = [];
for(var i = 0, j = data.length; i < j; ++i) {
var idString = data[i];
ids.push(idString.substring(0, idString.indexOf('_')));
}

elegance:
data.map(function(x){
return x.split('_')[0];
})
This IS part of the ECMA-262 standard.
But, if you care about supporting old outdated sub-par browsers, use jQuery (or whatever other framework you are using; almost all of them define a custom map function):
$.map(data, function(x){
return x.split('_')[0];
})

What you want to do is called a 'map.'
Some browsers support them, but if you want to be safe you can use underscore.js (http://documentcloud.github.com/underscore/)
You'd end up with either:
_(data).map(function(x){
return x.split('_')[0];
});
or
_.map(data, function(x){
return x.split('_')[0];
});

If you have a really big array it may be faster to join it to a string and split the string, rather than using any of the iterative methods to form it one by one.
var data = ["1111_3", "1231_54", "1143_76", "1758_12"];
var ids= data.join(' ').replace(/_\d+/g,'').split(' ');
alert(ids)
/* returned value: (Array)
1111,1231,1143,1758
*/

Related

D3 - How to merge 2 arrays based on their row index

I am working on visualization using D3 and need to merge 2 arrays based on row index:
var links =
[
{"source":"a0","target":"a0","s_portfolio":"a","t_portfolio":"a","SOURCE_TYPE":"APP","DES_TYPE":"APP"},
{"source":"a1","target":"a2","s_portfolio":"a","t_portfolio":"c","SOURCE_TYPE":"APP","DES_TYPE":"APP"},
{"source":"a1","target":"a2","s_portfolio":"a","t_portfolio":"c","SOURCE_TYPE":"APP","DES_TYPE":"APP"}
];
var files =
[
{"File_Desc":"","DataName":""},
{"File_Desc":"Date","DataName":"Dates.01012016"},
{"File_Desc":"Address","DataName":"Address.01012016"}
];
To get:
var result =
[
{"source":"a0","target":"a0","s_portfolio":"a","t_portfolio":"a","SOURCE_TYPE":"APP","DES_TYPE":"APP","File_Desc":"","DataName":""},
{"source":"a1","target":"a2","s_portfolio":"a","t_portfolio":"c","SOURCE_TYPE":"APP","DES_TYPE":"APP","File_Desc":"Date","DataName":"Dates.01012016"},
{"source":"a1","target":"a2","s_portfolio":"a","t_portfolio":"c","SOURCE_TYPE":"APP","DES_TYPE":"APP","File_Desc":"Address","DataName":"Address.01012016"}
]
If you can use late model JavaScript (aka ES2015),
the shortest path is something like:
var result = links.map((d,i) => Object.assign({}, d, files[i]));
This is short. It also doesn't modify either links or files (should you wish to use them stand-alone separately from result).
P.S.
The comments suggest you're concerned about the runtime of the alternative solutions. In general, they're all okay, esp. as the kind of one-time data setup common in d3 apps. But, if you have large datasets or run record merges often, then you might want to optimize.
If you're willing to update one of your existing record sets rather than create a fresh new one:
links.forEach((d,i) => Object.assign(d, files[i]));
After this, links has the updated records. This runs 7-10x faster than the other solutions, presumably because it's not creating a ton of new objects. If you're done with the original, un-merged links or files objects, there's no particular reason to avoid this kind of "destructive" or "in place" update. There's often little need to optimize one-time setup operations. But if you wanted or needed to do so, this is a strong way.
Try this:
var links = [
{"source":"a0","target":"a0","s_portfolio":"a","t_portfolio":"a","SOURCE_TYPE":"APP","DES_TYPE":"APP"},
{"source":"a1","target":"a2","s_portfolio":"a","t_portfolio":"c","SOURCE_TYPE":"APP","DES_TYPE":"APP"},
{"source":"a1","target":"a2","s_portfolio":"a","t_portfolio":"c","SOURCE_TYPE":"APP","DES_TYPE":"APP"}
];
var files = [
{"File_Desc":"","DataName":""},
{"File_Desc":"Date","DataName":"Dates.01012016"},
{"File_Desc":"Address","DataName":"Address.01012016"}
];
var result = [];
for(let i = 0; i < links.length; i++){
result[i] = Object.assign(links[i], files[i]);
}
console.log(result);
I'd probably iterate over one array with an array map and then in my callback function return a combined object using a function such as the one defined in this answer.
var result = links.map(combineLinkToFile);
function combineLinkToFile (link, index) {
var file = files[index];
return collect(link, file)
}
function collect() {
var ret = {};
var len = arguments.length;
for (var i=0; i<len; i++) {
for (p in arguments[i]) {
if (arguments[i].hasOwnProperty(p)) {
ret[p] = arguments[i][p];
}
}
}
return ret;
}
Using jQuery map() and extend() methods:
function mergeObjectsInArrays(arr1, arr2){
return $.map(arr1, function(el, i){
return $.extend(el, arr2[i]);
});
};
// then pass your arrays:
var result = mergeObjectsInArrays(links, files);

Create an array or object of elements with the same dynamic class

I currently the following jQuery collection / object:
[li.row-0, li.row-1, li.row-2, li-row-2, li.row-2, li.row-3]
Each class name is dynamically added to each element by a previous method. The only consistent part of the class name is row-. The number can be anywhere from 0 - ∞.
I want to create a new array or object of elements that are grouped by same dynamic class name:
[li.row-0]
[li.row-1]
[li.row-2, li.row-2, li.row-2, li.row-2]
[li.row-3]
The above is just a guess of the outcome, as I am not 100% sure how best to achieve this.
The aim is to be able to loop through .row-0, .row-1, .row-2, .row-3 and do something with the elements in each individual row.
I would do this :
var map = [].reduce.call(arr, function(map, v){
(map[v.className]||(map[v.className]=[])).push(v);
return map;
}, {});
var arr2 = [];
for (var className in map) arr2.push(map[className]);
The reduce builds a map having as keys the class names and with values the arrays of the elements having that class name.
I use [].reduce.call(arr, instead of arr.reduce( so that it works for standard arrays, jQuery collections, nodelists, etc.
Then the loop builds an array from that map. You might find the map more useful than the final array.
This shows you a general way of achieving this, though you're probably using elements rather than strings, but hopefully this will help
var tst = ['li.row-0','li.row-1','li.row-2','li.row-2','li.row-2','li.row-3'];
var grouped = [];
for(var i in tst)
{
var text = tst[i];
var num = text.replace('li.row-','');
if(!grouped[num]) grouped[num] = [];
grouped[num].push(text);
}
console.log(grouped);//[["li.row-0"], ["li.row-1"], ["li.row-2", "li.row-2", "li.row-2"], ["li.row-3"]]
Using elements:
var tst = [li.row-0,li.row-1,li.row-2,li.row-2,li.row-2,li.row-3];
var grouped = [];
for(var i in tst)
{
var text = tst[i].className;
var num = text.replace('row-','');
if(!grouped[num]) grouped[num] = [];
grouped[num].push(text);
}
console.log(grouped);//[["li.row-0"], ["li.row-1"], ["li.row-2", "li.row-2", "li.row-2"], ["li.row-3"]]
This method is more verbose and allows more complex grouping if need be (if other attributes come into play)
I would do something like the following:
var arr = ['li.row-0', 'li.row-1', 'li.row-2', 'li.row-2', 'li.row-2', 'li.row-3'];
var result = {};
$.each(arr, function (index, item) {
var ind = item.toString().split('row-')[1];
(result[ind] || (result[ind] = [])).push(item);
});
console.log(result);

How to split a URL string with parameters into an array using JavaScript

I'm trying to break up a string like this one:
fname=bill&mname=&lname=jones&addr1=This%20House&...
I want to end up with an array indexed like this
myarray[0][0] = fname
myarray[0][1] = bill
myarray[1][0] = mname
myarray[1][1] =
myarray[2][0] = lname
myarray[2][1] = jones
myarray[3][0] = addr
myarray[3][1] = This House
The url is quite a bit longer than the example. This is what I've tried:
var
fArray = [],
nv = [],
myarray = [];
fArray = fields.split('&');
// split it into fArray[i]['name']="value"
for (i=0; i < fArray.length; i++) {
nv = fArray[i].split('=');
myarray.push(nv[0],nv[1]);
nv.length = 0;
}
The final product is intended to be in 'myarray' and it is, except that I'm getting a one dimensional array instead of a 2 dimensional one.
The next process is intended to search for (for example) 'lname' and returning the index of it, so that if it returned '3' I can then access the actual last name with myarray[3][1].
Does this make sense or am I over complicating things?
Your line myarray.push(nv[0],nv[1]); pushes two elements to the array myarray, not a single cell with two elements as you expect (ref: array.push). What you want is myarray.push( [nv[0],nv[1]] ) (note the brackets), or myarray.push(nv.slice(0, 2)) (ref: array.slice).
To simplify your code, may I suggest using Array.map:
var q = "foo=bar&baz=quux&lorem=ipsum";
// PS. If you're parsing from a-tag nodes, they have a property
// node.search which contains the query string, but note that
// it has a leading ? so you want node.search.substr(1)
var vars = q.split("&").map(function (kv) {
return kv.split("=", 2);
});
For searching, I would suggest using array.filter:
var srchkey = "foo";
var matches = vars.filter(function (v) { return v[0] === srchkey; });
NB. array.filter will always return an array. If you always want just a single value, you could use array.some or a bespoke searching algorithm.
for (var i = 0; i < fArray.length; i++) {
nv = fArray[i].split('=');
myarray.push([nv[0],nv[1]]);
}
nv.length = 0; is not required, since you're setting nv in each iteration of the for loop.
Also, use var i in the for-loop, otherwise, you're using / assigning a global variable i, that's asking for interference.

jquery split() issue

Hopefully this is easy for someone.
I have a set of checkboxes with values 1,2,3 etc with the same name attribute (cp_bundle).
I use the following code to get a comma-delimited list of those checkboxes.
var hl_calling_plan_bundle = $('input[name="cp_bundle"]:checked').getCheckboxVal() || "";
jQuery.fn.getCheckboxVal = function(){
var vals = [];
var i = 0;
this.each(function(){
vals[i++] = jQuery(this).val();
});
return vals;
}
if I check the first and third checkboxes, the following will be returned:
1,3
Then, I want to run a test to see whether a particular value (e.g. "3") exists in the the returned variable
But, I can't get past the split of the variable using the following:
var aCallingBundle = hl_calling_plan_bundle.split(",");
This gives the error:
hl_calling_plan_bundle.split is not a function
Any idea what's going on?
hl_calling_plan_bundle is an array. You have to use array operations on it, not string operations.
If you want to know if the value 3 is in the array, then you have to search the array for it. There are many ways to search an array, but since you have jQuery, it's easy to use the .inArray() function:
var index = $.inArray(3, hl_calling_plan_bundle);
if (index != 1) {
// found 3 in the array at index
}
Incidentally, you may want to simplify your function like this:
jQuery.fn.getCheckboxVal = function(){
var vals = [];
this.each(function(){
vals.push(this.value);
});
return vals;
}
or this way:
jQuery.fn.getCheckboxVal = function(){
return(this.map(function(){return(this.value)}).get());
}
split() is a String method, it does not exist on an Array.
When you say the following is returned 1,3, you may be implicitly calling the String's toString() method, which will by default join() the array members with a comma. If you explicitly called toString(), then you could call split(), but that would be an anti pattern.
You don't need to split the string, you can just use RegEx to search:
var str = '1,3,22,5';
/\b1\b/.test(str); // true
/\b2\b/.test(str); // false
/\b3\b/.test(str); // true
/\b5\b/.test(str); // true
/\b22\b/.test(str); // true
Making it a function:
String.prototype.findVal = function(val){
var re = new RegExp('\\b' + val + '\\b');
re.lastIndex = 0;
return re.test(this);
};
str.findVal(2); // false
str.findVal(22); // true
To get the checkboxes:
var cbs = document.getElementsByName('cp_bundle');
To get arrays of all values and the checked values:
var allValues = [];
var checkedValues = [];
for (var i=0, iLen=cbs.length; i<iLen; i++) {
if (cbs[i].checked) checkedValues.push(cbs[i].value);
allValues[i] = cbs[i].value;
}

Array read problem for map of vectors of strings in javascript

I am a newbie in JS. Here is my code and I believe it should work... but it doesn't.
var pop = new Array();
pop['la'] = new Array('nt','gb','te');
pop['sa'] = new Array('nt','gb');
pop['ha'] = new Array('pc','pa');
var _ecpop="la";
for (var i = 0; i < pop[_ecpop].length; i++)
{
document.write(pop[_ecpop][i]);
}
I just do not know any alternate way to have a map of vectors of a string.
Thanks,
Amir.
That's not an Array, but a Javascript Object, containing Arrays in it's properties. You can use Object and Array literals for that. The advantage is that your code looks much cleaner. There are seldom reasons to use new Array or new Object in javascript code (see for example this SO Question).
var pop = {
la: ['nt','gb','te'],
sa: ['nt','gb'],
ha: ['pc','pa']
}
now you can use
for (var i = 0; i < pop.la.length; i++) {
console.log(pop.la[i]);
}
if a property label is stored in a variable (like you _ecpop), you can use bracket notiation to retrieve it's value:
var laArr = pop[_ecpop];
for (var i = 0; i < laArr.length; i++) {
console.log(laArr[i]);
}
The other way around you can assign a label to an Object:
var _ecpop = 'la';
pop[_ecpop] = ['nt','gb','te'];
document.write is not the preferred way to put things on your page. It's better and just as easy to use some element with an id, and write output to it using innerHTML, for example
document.getElementById('myOutput').innerHTML = '[some output here]';
In javascript, an array can only have numeric indexes, if you want to use textual indexes, you should use object instead.
var pop = new Object();
or
var pop = {};
and then:
pop['la'] = new Array('nt','gb','te');
However, as an object is not an array, it has no length member, but just as an array you can use the for..in to go through all of its values.
Using document.write is not a good choice as it only works during the document loading, not after it. Try to use text nodes or innerhtml instead.

Categories