I need to be able to convert an array into a new array containing multiple objects. For example, if I have this array:
["name", "Tom", "id", "48688", "name", "Bob", "id", "91282"]
I want to be able to convert it into this:
[{
"name": "Tom",
"id": "48688"
}, {
"name": "Bob"
"id": "91282"
}]
Use a for
loop that increments its iteration by 4
, like so:
let results = [];
for(let i = 0; i < array.length; i += 4) { // increment i by 4 to get to the start of the next object data
results.push({
id: array[i + 3], // array[i + 0] is the string "name", array[i + 1] is the name,
name: array[i + 1] // array[i + 2] is the string "id" and array[i + 3] is the id
});
}
Demo:
let array = ["name", "Tom", "id", "48688", "name", "Bob", "id", "91282", "name", "Ibrahim", "id", "7"]; let results = []; for(let i = 0; i < array.length; i += 4) { results.push({ id: array[i + 3], name: array[i + 1] }); } console.log(results);
It is common to see a zip
function taking a key k
and a value v
and create an object with them:
const zip =
(k, v) =>
({[k]: v});
zip("name", "Tom");
//=> {name: "Tom"}
If both key and value are in an array you can spread it in a zip call like that zip(...arr)
. Or you can modify the signature a little bit:
const zip =
([k, v]) =>
({[k]: v});
zip(["name", "Tom"]);
//=> {name: "Tom"}
If the array contains multiple pairs of keys and values then we can design a recursive version of zip
:
const Nil = Symbol();
const zip =
([k = Nil, v = Nil, ...xs], o = {}) =>
k === Nil && v === Nil
? o
: zip(xs, (o[k] = v, o));
zip(["name", "Tom", "id", "48688"]);
//=> {name: "Tom", id: "48688"}
We can now think about slicing your array into chunks of equal number of pairs and apply zip
to each chunk.
First let's write a slices
function that will cut an array into slices of n elements:
const slices =
(xs, n, ys = []) =>
xs.length === 0
? ys
: slices(xs.slice(n), n, (ys.push(xs.slice(0, n)), ys));
slices(["name", "Tom", "id", "48688", "name", "Bob", "id", "91282"], 4);
//=> [["name", "Tom", "id", "48688"],["name", "Bob", "id", "91282"]]
We can now apply zip
to each chunk:
slices(["name", "Tom", "id", "48688", "name", "Bob", "id", "91282"], 4)
.map(chunk => zip(chunk));
//=> [{name: "Tom", id: "48688"},{name: "Bob", id: "91282"}]
const Nil = Symbol(); const zip = ([k = Nil, v = Nil, ...xs], o = {}) => k === Nil && v === Nil ? o : zip(xs, (o[k] = v, o)); const slices = (xs, n, ys = []) => xs.length === 0 ? ys : slices(xs.slice(n), n, (ys.push(xs.slice(0, n)), ys)); console.log( slices(["name", "Tom", "id", "48688", "name", "Bob", "id", "91282"], 4) .map(chunk => zip(chunk)) );
I see questions like this very, very often, so I made a little converter that accomplishes this particular goal:
// input var inputArray = ["name", "Tom", "id", "48688", "name", "Bob", "id", "91282"] var sizeOfObjects = 2; // amount of entries per object // function function convert(array, size) { var newArray = [] //set up an array var res3 = array.reduce((acc, item, index) => { if (index % 2 == 0) { // if the index is even: acc[`${item}`] = array[index+1]; // add entry to array } if (Object.keys(acc).length == size) { // if the desired size has been reached: newArray.push(acc); // push the object into the array acc = {}; // reset the object } return acc; // preserve accumulator so it doesn't get forgotten }, {}); // initial value of reducer is an empty object return newArray; //return the array } console.log(convert(inputArray, sizeOfObjects));
Hopefully this helps people who are looking for an answer for this kind of question.
If you're looking to just create a single object, look at this other question/answer: Create object from array
You could take a dynamic approach by using an object for keeping track of the target index for same named keys.
const getArray = data => { let indices = {}, result = [], i = 0; while (i < data.length) { const [key, value] = data.slice(i, i += 2); indices[key] ??= 0; (result[indices[key]++] ??= {})[key] = value; } return result; }, data1 = ["name", "Tom", "id", "48688", "name", "Bob", "id", "91282"], data2 = ["name", "Tom", "id", "48688", "color", "green", "name", "Bob", "id", "91282", "color", "red"]; console.log(getArray(data1)); console.log(getArray(data2));
.as-console-wrapper { max-height: 100% !important; top: 0; }
We can use %
operator to decide whether we find an object to insert into array or not:
const data = ["name", "Tom", "id", "48688", "name", "Bob", "id", "91282"]; makeObjectArray = arr => { const result = [], temp = []; arr.forEach((a, i)=>{ if (i % 2 == 0) temp.push({ [arr[i]]: arr[i + 1]}) if (i % 3 == 0 && i != 0) { result.push(Object.assign({}, ...temp)); temp.length = 0; } }) return result; } console.log(makeObjectArray(data))
you can break the array into smaller chunks of the desired size with a helper function like:
function chunk(to_chunk, chunk_size) {
var output = [];
if(to_chunk.length > chunk_size) {
output.push(to_chunk.slice(0, chunk_size));
output.push(chunk(to_chunk.slice(chunk_size)));
return output;
} else {
return to_chunk;
}
}
Then you can map the result with other function to return your desired object:
var final = chunk(seed, 4).map((x) => myObject(x));
function myObject(seed) {
var output = {};
output[seed[0]] = seed[1];
output[seed[2]] = seed[3];
return output;
}
I think this approach is nice in terms of readability, putting all together you have:
var seed = ["name", "Tom", "id", "48688", "name", "Bob", "id", "91282"]; var final = chunk(seed, 4).map((x) => myObject(x)); console.log(final); function chunk(to_chunk, chunk_size) { var output = []; if(to_chunk.length > chunk_size) { output.push(to_chunk.slice(0, chunk_size)); output.push(chunk(to_chunk.slice(chunk_size))); return output; } else { return to_chunk; } } function myObject(seed) { var output = {}; output[seed[0]] = seed[1]; output[seed[2]] = seed[3]; return output; }
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.