Adam Bradbury
Adam Bradbury

Reputation: 91

Create one object out of two separate arrays based on index

I'm trying to take this array of arrays,

const parsedCsvData = [
  [
    "Passage",
    "Percentage of",
    "constraint2",
    "1",
    "2",
    "",
    "",
    "",
    "",
    "",
    "",
    ""
  ],
  [
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "Avg A Param",
    "",
    "0.3",
    "0.9"
  ],
  [
    "Item",
    "Include",
    "constraint1",
    "1",
    "4",
    "",
    "",
    "",
    "",
    "",
    "",
    ""
  ],
  [
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "Item Identifier",
    "I105_15201",
    "",
    ""
  ]
]

and populate this object with their values

const template = {
  "attributeName": "",
  "constraintType": "",
  "objectType": "",
  "filters": [
    {
      "objectType": "",
      "attributeName": "",
      "values": "",
      "valueLowerBound": "",
      "valueUpperBound": ""
    }
  ],
  "upperBound": "",
  "description": "",
  "lowerBound": ""
}

each array from parsedCsvData was a row in a CSV file I parsed. Each value in the array of arrays is indexed based off another array

const csvHeaders = [
  "objectType",
  "constraintType",
  "description",
  "lowerBound",
  "upperBound",
  "attributeName",
  "referenceValue",
  "scope",
  "filters",
  "values",
  "valueLowerBound",
  "valueUpperBound"
]

For example, in the first sub array of parsedCsvData Passage is at index 0 and the value for objectType in csvHeaders. Similarly, description is at index 2 and is constraint1 and constraint2 respectively.

Additionally, if there exists a filters value at index 8 in the csv a new row was created. After parsing, this created a new sub array for each filter value. However, each filters value and the following three, values, valueLowerBound and valueUpperBound belong in the same template object as a subarray under the filters key.

Here is an example of the output I am trying to accomplish given what I posted above. Never mind the empty key/value pairs.

[{
  "constraintType": "Percentage of",
  "objectType": "Passage",
  "filters": [
    {
      "attributeName": "Avg A Param",
      "values": "",
      "valueLowerBound": "0.3",
      "valueUpperBound": "0.9"
    } // there may be multiple filter objects as part of this array
  ],
  "upperBound": "2",
  "description": "constraint2",
  "lowerBound": "1"
},
{
  "constraintType": "Include",
  "objectType": "Item",
  "filters": [
    {
      "attributeName": "Item Identifier",
      "values": "I105_15201",
      "valueLowerBound": "",
      "valueUpperBound": ""
    }
  ],
  "upperBound": "4",
  "description": "constraint1",
  "lowerBound": "1"
}
]

I've tried mapping the csvHeaders array, attempting to use their indices and then do a map of the the parsedCsvData values and assign them to the template object, but can't seem to get it to work. Any help would be much appreciated.

Upvotes: 0

Views: 45

Answers (1)

Nina Scholz
Nina Scholz

Reputation: 386550

An approach by checking the first element of the nested arra for either assign a new object or assign a new nested object.

    const
        parsedCsvData = [["Passage", "Percentage of", "constraint2", "1", "2", "", "", "", "", "", "", ""], ["", "", "", "", "", "", "", "", "Avg A Param", "", "0.3", "0.9"], ["Item", "Include", "constraint1", "1", "4", "", "", "", "", "", "", ""], ["", "", "", "", "", "", "", "", "Item Identifier", "I105_15201", "", ""]],
        template = ["objectType", "constraintType", "description", "lowerBound", "upperBound", "xxxx", "referenceValue", "scope", "attributeName", "values", "valueLowerBound", "valueUpperBound"],
        result = parsedCsvData.reduce((r, a) => {
            const
                assign = (object, target, value) => {
                    const
                        keys = target.split('.'),
                        last = keys.pop();

                    keys.reduce((o, k) => o[k] = o[k] || {}, object)[last] = value;
                };

            if (a[0]) {
                r.push(a.reduce((t, v, i) => {
                    if (v) assign(t, template[i], v);
                    return t;
                }, {}));
            } else {
                r[r.length - 1].filters = r[r.length - 1].filters || [];
                r[r.length - 1].filters.push(a.reduce((t, v, i) => {
                    if (v) assign(t, template[i], v);
                    return t;
                }, {}));
            }
            return r;
        }, []);
        
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 1

Related Questions