1

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"
}]
customcommander
  • 17,580
  • 5
  • 58
  • 84
Lemondoge
  • 959
  • 4
  • 17

6 Answers6

1

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);
ibrahim mahrir
  • 31,174
  • 5
  • 48
  • 73
1

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))
  
);
customcommander
  • 17,580
  • 5
  • 58
  • 84
0

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

Lemondoge
  • 959
  • 4
  • 17
0

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; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
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))
StepUp
  • 36,391
  • 15
  • 88
  • 148
0

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;
}
MarioZ
  • 981
  • 7
  • 16