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"
}]
3
  • How did you get it like this in the first place? This should be an array of objects from the start. Commented Nov 1, 2020 at 19:39
  • This is a question that I self-answered and put my answer to as a community wiki. The question is really just an example. Commented Nov 1, 2020 at 19:56
  • what, if you have three properties for an object? do you need to know this in advance? why? Commented Nov 1, 2020 at 21:15

6 Answers 6

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))
  
);

Sign up to request clarification or add additional context in comments.

Comments

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);

Comments

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

Comments

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))

Comments

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;
}

Comments

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; }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.