w3debugger
w3debugger

Reputation: 2102

Transform key/value pairs object into array of objects using Vanilla JS

Below is the object I have

var data = {
  sku: ['1', '2', '3', '4'],
  color: [],
  season: ['winter', 'summer'],
}

Below is the output I'm expecting

data = [
  { sku: '1', season: 'winter'},
  { sku: '2', season: 'summer'},
  { sku: '3'},
  { sku: '4'},
]

Below is the working script but not easy to read. Please suggest if you have any better suggestion.

var data = {
  sku: ['1', '2', '3', '4'],
  color: [],
  season: ['winter', 'summer'],
}

var arr = Object.entries(data)
  .filter(item => item[1] && item[1].length) // remove empty values
  .sort((x, y) => y[1].length - x[1].length) // bring lengthy value to first

var final = arr[0][1].map((a, index) =>
  arr.reduce((b, acc) => ({
    ...b,
    ...(acc[1][index] && { [acc[0]]: acc[1][index] }),
  }), {})
);

console.log(final);

Upvotes: 0

Views: 520

Answers (2)

Ori Drori
Ori Drori

Reputation: 191976

Using vanilla JS you can transpose (zip) the arrays using Array.from() with Array.map(). Then map the array of arrays, combine to pairs with the original keys, and filter out pairs with value that is undefined. Afterwards you can convert the array of pairs to an object using Object.fromEntries():

const zip = (...arr) =>
  Array.from({ length: Math.max(...arr.map(a => a.length)) }, (_, i) => 
    arr.map(a => a[i])
  )

const createObject = obj => {
  const keys = Object.keys(obj)

  return arr => Object.fromEntries(
    keys.map((key, i) => [key, arr[i]])
      .filter(([, val]) => val !== undefined)
  )
}

const fn = obj => zip(...Object.values(obj)).map(createObject(obj))

const data = {
  sku: ['1', '2', '3', '4'],
  color: [],
  season: ['winter', 'summer'],
}

const result = fn(data)

console.log(result)

With lodash Zip the arrays to an array with sub-arrays that each contains all the values of an object. Then map the array of arrays, and use _.zipObject() to combine the original keys, with a sub-array of values to an object, and then _.omit() the keys with undefined values.

const { omitBy, zipObject, isUndefined, zip } = _

const createObject = obj => {
  const keys = Object.keys(obj)

  return arr => omitBy(zipObject(keys, arr), isUndefined)
}

const fn = obj => zip(...Object.values(obj)).map(createObject(obj))

const data = {
  sku: ['1', '2', '3', '4'],
  color: [],
  season: ['winter', 'summer'],
}

const result = fn(data)

console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js" integrity="sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG+ljU96qKRCWh+quCY7yefSmlkQw1ANQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

Upvotes: 1

Peter Seliger
Peter Seliger

Reputation: 13376

function createListOfObjectsFromValuesConfig(config) {
  const [

    // the entry list with the maximum length `value` list.
    primaryEntryList,
    // the list of all remaining entry lists.
    ...listOfSecondaryEntries

  ] = Object
    // get an array of entries, each entry an array itself,
    // a tuple of an entry's key and value.
    .entries(config)
    // sort the array of entry arrays descending by
    // comparing the `value` array's `length`properties.
    .sort((a, b) => b[1].length - a[1].length);

  const [

    primaryKey,
    primaryValueList,

  ] = primaryEntryList;

  return primaryValueList
    .map((primaryValue, primaryIndex) => {

      return listOfSecondaryEntries
        .reduce((dataItem, [secondaryKey, secondaryValueList]) => {

          if (secondaryValueList.hasOwnProperty(primaryIndex)) {

            // if possible aggregate the item's
            // initially provided base data.
            Object.assign(dataItem, {

              [secondaryKey]: secondaryValueList[primaryIndex]
            });
          }
          return dataItem;

        }, { [primaryKey]: primaryValue }); // create the item's base.
    });
}

var data = {
  sku: ['1', '2', '3', '4'],
  color: [],
  season: ['winter', 'summer'],
};

console.log(
  'createListOfObjectsFromValuesConfig(data) ...',
  createListOfObjectsFromValuesConfig(data)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

Upvotes: 1

Related Questions