Ecaz
Ecaz

Reputation: 111

Turning this string into an object

I have this string (which is called data)

||id: ticket/327364|Subject: TestSubject|Due: 2018||--||id: ticket/327366|Subject: TestTwo|Due: 2018|||

That I want to turn into an object that is accessible using key/values. Step 1 is splitting the string on "--" and removing all the "|" signs. Which I did like this

var dataArray = [];
data.split("--").forEach(function(x) {
    var arr = x.split("|");
    arr = arr.filter(function(e) {
        return e;
    });
    dataArray.push(arr);
});

This gives me a multidimensional array

[Array(3), Array(3)]
    0: ["id: ticket/327364", "Subject: Beställning av inkoppling", "Due: Ej inställd"]
    1: ["id: ticket/327366", "Subject: Beställning av inkoppling", "Due: Ej inställd"]

And this is where I am stuck, because I want to split each of these arrays on ":". So Object.Due will give me the due-date and Object.Subject gives me the Subject etc. Also, it's not always going to be id, Subject, and Due. Sometimes it might be less or more entries.

I have tried this

var result = {};
dataArray.forEach(function(x) {
    x.forEach(function(y) {
       var newArr = y.split(":");
       newArr[1] && (result[newArr[0]] = newArr[1]);
    });
});

Which gives me exactly what I want, it gives me an object like this.

{id: " ticket/327366", Subject: " TestTwo", Due: " 2018"}

However, result only contains the data from the last array. It's like it overwrites the first one. Any suggestions on how to re-do this? Also, it feels like an awful lot of loops but I've only been dabbling with JS for a day or two so I haven't really figured out a different way of doing it.

Upvotes: 0

Views: 85

Answers (4)

Gorka Hernandez
Gorka Hernandez

Reputation: 3958

Here's a different approach that avoids unwanted referencing:

const input = '||id: ticket/327364|Subject: TestSubject|Due: 2018||--||id: ticket/327366|Subject: TestTwo|Due: 2018|||';

const result = input
  .split('--')
  .map(subArray => {
    const resultObject = {};
    const filtered = subArray
      .split('|')
      .filter(item => item.length > 0);

    for (let element of filtered) {
      const [key, value] = element.split(':');
      resultObject[key] = value.trim();
    }
    return resultObject;
  });

console.log(result);

In your version, you are setting the value of the respective key to the new value, since the objects have repeated keys, they are being overwritten by the latest.

Upvotes: 1

trincot
trincot

Reputation: 350147

In the second code block you are building only one object: you want an array, yet result is not an array. Move that object declaration inside the outer loop, and push that object to the final array at the end of each iteration. See the comments in your code where I made changes:

var data = '||id: ticket/327364|Subject: TestSubject|Due: 2018||--||id: ticket/327366|Subject: TestTwo|Due: 2018|||';

var dataArray = [];
data.split("--").forEach(function(x) {
    var arr = x.split("|");
    arr = arr.filter(function(e) {
        return e;
    });
    dataArray.push(arr);
});

var resultArray = []; // <--- final array
dataArray.forEach(function(x) {
    var result = {}; // <--- one object per iteration
    x.forEach(function(y) {
       var newArr = y.split(":");
       newArr[1] && (result[newArr[0]] = newArr[1]);
    });
    resultArray.push(result); // <--- push it
});
console.log(resultArray);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Alternative, functional programming way

Here is an alternative way, which uses several ES6 features such as spread syntax, arrow functions, Object.assign and computed property syntax:

const data = '||id: ticket/327364|Subject: TestSubject|Due: 2018||--||id: ticket/327366|Subject: TestTwo|Due: 2018|||';

const dataArray = data.split("--").map(x =>
    Object.assign(...
               x.split("|")
                .filter(e => e)
                .map(s => s.split(':'))
                .map(([key, value]) => ({ [key]: value.trim() }))
    )
);

console.log(dataArray);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 2

Bergi
Bergi

Reputation: 664405

You want one result per dataArray entry, not one overall. So put the object creation it in the right place, and collect them in an array:

var results = dataArray.map(function(x) {
    var result = {};
    for (var y of x) {
       var newArr = y.split(":");
       if (newArr[1]) result[newArr[0]] = newArr[1];
    }
    return result;
});

Upvotes: 1

Hugo Montoya Vazquez
Hugo Montoya Vazquez

Reputation: 32

Well, that's because, as I understand, you are creating a single object each time in the result variable, so you are overwriting the result at each time in the loop. I think you sould insert the result object in an Array of results and iterate through it inserting in every cicle of the loop the result in the array with .push().

Don't know if that make sense for you.

Upvotes: 1

Related Questions