-3

I have this hash:

{
 a: [1,2],
 b: [1,2,3]
}

I need to generate a string like this:

a=1&a=2&b=1&b=2&b=3

How can I solve this problem ? I'm taking a look at lodash but I cant solve it.

Thanks.

CodingGorilla
  • 19,196
  • 3
  • 43
  • 62
  • 3
    What have you tried? Why are you looking at lodash? Why not use a simple loop? – Bergi Mar 30 '16 at 14:19
  • 1
    Maybe habe a look at [Convert javascript object to URL parameters](http://stackoverflow.com/q/22678346/1048572) for some ideas – Bergi Mar 30 '16 at 14:23
  • I would still hold off on ES6 solutions unless you **know** that enough of your users support the features you want. I'd stick to one of the simple loops that were proposed (including my answer) – Martin Mar 30 '16 at 14:31
  • 2
    **This is not a duplicate of the question shown**! A string like `a=1&a=2` would be *overwriting* the previous `a` variable. This is NOT what the original poster is asking for. – Martin Mar 30 '16 at 14:42
  • 1
    I agree with @Martin: Not the same question, and does not provide a suitable solution. Thus I have flagged for reopen... there *might* be a duplicate out there, but the proposed one is not it – musefan Mar 30 '16 at 14:50

7 Answers7

5

Using javascript Object.keys(), map() and join() with ES6 arrow function

var arr = {
  a: [1, 2],
  b: [1, 2, 3]
};
var res = Object.keys(arr).map(v => arr[v].map(v1 => v + '=' + v1).join('&')).join('&');
document.write(res);

Or without arrow function

var arr = {
  a: [1, 2],
  b: [1, 2, 3]
};

var res = 
    // get object keys
    Object.keys(arr)
// iterate over object keys and iterate
.map(function(v) {
  // iterate over inner array
  return arr[v].map(function(v1) {
    // generate prefered string and return 
    return v + '=' + v1
    // cconcatenate string array
  }).join('&')
  // concatenate string array
}).join('&');

document.write(res);
Pranav C Balan
  • 110,383
  • 23
  • 155
  • 178
  • Or, just for fun, instead of two `joins`, if the input doesn't contain any comas: `Object.keys(arr).map(v => arr[v].map(v1 => v + '=' + v1)).join().replace(/,/g, '&')` :) – XCS Mar 30 '16 at 15:00
4

For a nice ES5 solution:

function hashToString(hash) {

    var str = '';
    for ( prop in hash ) {
        if ( !hash.hasOwnProperty(prop) ) continue;
        for (var i = 0; i < hash[prop].length; i++) {
            str += prop + '=' + hash[prop][i] + '&';
        };
    }
    str = str.slice(0, str.length-1);
    return str;

}

Try that out!

It works:

enter image description here


Okay! So what's going on?

First, you want to loop through each item on the first level.

You do this with a for ... in loop. You should be checking hasOwnProperty so you don't go through unexpected prototype properties.

Then, within that first loop, you want to loop through the items in the current item:

We'll do that with a regular for loop because these items are just arrays.

In here, we want to adjust our string:

str += prop + '=' + hash[prop][i] + '&';

This adds our property name (saved as prop from the for ... in loop), then the value in that property's array at the given index i. We'll leave it with a trailing & that we will remove just outside of the loop.

Martin
  • 5,944
  • 6
  • 39
  • 63
  • I think you slightly exaggerated your answer, but it's 100% correct and useful. Grab a +1 :). – Fka Apr 07 '16 at 06:35
  • 1
    Yeah, it is a bit long winded. But when I started off, I learned *a lot* from long answers like this. They can show you not just the correct code, but the way to *think* when coding. I like to show what my train of thought is when I put it together, because often time that mode of thinking will help in future problems :) – Martin Apr 07 '16 at 16:23
1

Use a for in loop to iterate over each property in your hash object, and from there, add each value to the string, like so:

function hashToQueryString(hash) {
    var query = '';
    for (key in hash) {
        for (i=0; i<=key.length; i++) {
            query += key+'='+ myJSON[key]+'&';
        }
    }
    //remove the trailing &
    query = query.substr(0, query.length -1);
    return query;
}

(Keep in mind that you should also be checking that each property in hash contains a valid array, and that you're not accidentally enumerating any properties you don't want)

dcastrodale
  • 87
  • 1
  • 4
0

You could use qs for that. It will also handle all the encoding needed if you happen to go beyond integers.

qs.stringify({
    a: [1,2],
    b: [1,2,3]
}, { indices: false });
Li0liQ
  • 10,900
  • 33
  • 52
  • 1
    this is why there are sooo many libraries, such a simple task with a couple lines of code, why a new library to do it :( – musefan Mar 30 '16 at 14:24
  • @musefan Those libraries free up your brain power so you could spend it on really creative tasks instead of ones that have already been properly solved by others. – Li0liQ Mar 30 '16 at 14:26
  • @Li0liQ That's not a good reason to bring in a library for one task. – Martin Mar 30 '16 at 14:30
  • 1
    If you need the rest of the library, maybe... if you need this one tiny thing, then it's quicker to write own code than to find, install and learn a library – musefan Mar 30 '16 at 14:32
  • @Martin Fair enough. However, have you noticed that among the 7 answers suggested only two took into account url encoding? Isn't it a good enough reason to rely on a thoroughly tested library? And if the code volume is of concern, just use [rollup](https://github.com/rollup/rollup). – Li0liQ Mar 30 '16 at 19:41
  • Well the poster is not asking about url encoding. So no, I definitely would not recommend using a library for query string or url encoding. – Martin Mar 30 '16 at 19:45
0

If you have to stay with poor old ES5, and don't want to use another library for a simple task:

var myHash = {
   a: [1,2],
   b: [1,2,3]
}
var myString = '';
Object.keys(myHash).map(function(key, index) {
  myHash[key].map(function(value) {
    myString += (myString ? '&' : '') + key + '=' + value;
  });
});

jsfiddle

MarcoS
  • 16,647
  • 23
  • 89
  • 161
0

I am sure there is a cleaner way, but here is some options with reduce and map.

var obj = {
 a: [1,2],
 b: [1,2,3]
};

var params = Object.keys(obj).reduce( function (arr, key){
    arr.push(key + "=" + obj[key].join("&" + key + "="))
    return arr; 
}, []).join("&");

or if the values need to be encoded for the querystring

var params = Object.keys(obj).reduce( function (arr, key){
    var mapped = obj[key].map( function (val) { return key + "=" + encodeURIComponent(val); }).join("&");
    arr.push(mapped)
    return arr; 
}, []).join("&");
epascarello
  • 195,511
  • 20
  • 184
  • 225
0

let hash = {
  a: [1, 2],
  b: [1, 2, 3]
};
let str = '';
for (let key in hash) {
  for (let value of hash[key]) {
    str += `${key}=${value}&`;
  }
}
alert(str.slice(0, -1));
Lewis
  • 13,134
  • 12
  • 62
  • 81