5

I have an array of objects with the following structure:

 var varientSections = [
  {
    type: "frame",
    values: ["black", "white", "wood"]
  },
  {
    type: "finish",
    values: ["matte", "glossy"]
  }
];

I want to get the combination of the array values and create a new list with it. Right now, I am able to retrieve the combination from the nested array values using the method called getCombination(varientSections). However, I do not know how to create a new list with the following structure:

var results = [
  {
    attributes: [
      {
        type: "frame",
        value: "black"
      },
      {
        type: "finish",
        value: "matte"
      }
    ]
  },
  {
    attributes: [
      {
        type: "frame",
        value: "black"
      },
      {
        type: "finish",
        value: "glossy"
      }
    ]
  },
  {
    attributes: [
      {
        type: "frame",
        value: "white"
      },
      {
        type: "finish",
        value: "matte"
      }
    ]
  },
  {
    attributes: [
      {
        type: "frame",
        value: "white"
      },
      {
        type: "finish",
        value: "glossy"
      }
    ]
  },
  {
    attributes: [
      {
        type: "frame",
        value: "wood"
      },
      {
        type: "finish",
        value: "matte"
      }
    ]
  },
  {
    attributes: [
      {
        type: "frame",
        value: "wood"
      },
      {
        type: "finish",
        value: "glossy"
      }
    ]
  }
];

Below is my code:

function getCombinations(arr) {
  if (arr.length === 0) {
    return [[]];
  }

  let [current, ...rest] = arr;
  let combinations = getCombinations(rest);

  var result = current.values.reduce(
    (accumulator, currentValue) => [
      ...accumulator,
      ...combinations.map(c => [currentValue, ...c])
    ],
    []
  );
  console.log("result is ");
  console.log(result);
  return result;
}

let varientCombinations = getCombinations(varientSections);
console.log(varientCombinations);

let updatedVarientDetails = [];
varientSections.forEach((varientSection, index) => {
  let type = varientSection.type;
  varientCombinations.forEach(combination => {
    let obj = [
      {
        type: type,
        value: combination[index]
      },
    ];
    updatedVarientDetails.push(obj);
  });
});

console.log(updatedVarientDetails);
3
  • Is it possible for you just to use JavaScript concat? Commented Jul 10, 2019 at 13:45
  • Hi @MaikenMadsen thanks for the reply. What do you mean? I am open to any method! I just want to produce the list with the following structure that I mentioned above. Commented Jul 10, 2019 at 13:47
  • Here is a simple example from w3school: w3schools.com/jsref/jsref_concat_array.asp Commented Jul 10, 2019 at 13:52

2 Answers 2

6

You could get the cartesian product and give it later the wanted style. The names and values are taken form the handed over object.

The algorithm takes all key/value pairs and has a stric view to the values, that means if an array is found or an object, hence w && typeof w === "object", the actual part is taken an used for adding additional key/value pairs.

For example a small object with two properties

{ a: 1, b: [2, 3] }

yields

[
    { a: 1, b: 2 },
    { a: 1, b: 3 }
]

A bit more advanced object, like

{ a: 1, b: { c: { d: [2, 3], e: [4, 5] } } }

yields the same structure as given

[
    {
        a: 1,
        b: {
            c: { d: 2, e: 4 }
        }
    },
    {
        a: 1,
        b: {
            c: { d: 2, e: 5 }
        }
    },
    {
        a: 1,
        b: {
            c: { d: 3, e: 4 }
        }
    },
    {
        a: 1,
        b: {
            c: { d: 3, e: 5 }
        }
    }
]

Thant means, from any found sub object the cartesian product is taken and combined with the actual values.

const
    getCartesian = object => Object.entries(object).reduce(
        (r, [key, value]) => {
            let temp = [];
            r.forEach(s =>
                (Array.isArray(value) ? value : [value]).forEach(w =>
                    (w && typeof w === "object" ? getCartesian(w) : [w]).forEach(x =>
                        temp.push({ ...s, [key]: x })
                    )
                )
            );
            return temp;
        },
        [{}]
    ),
    data = [{ type: "frame", value: ["black", "white", "wood"] }, { type: "finish", value: ["matte", "glossy"] }],
    result = getCartesian(data)
        .map(o => ({ attributes: Object.assign([], o).map(({ ...o }) => o) }));

console.log(result);

console.log(getCartesian({ a: 1, b: { c: { d: [2, 3], e: [4, 5] } } }));
.as-console-wrapper { max-height: 100% !important; top: 0; }

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

1 Comment

Is it possible if you can write some comment for me to understand?
3

You could simplify it to this:

var variantSections = [
  {
    type: "frame",
    values: ["black", "white", "wood"]
  },
  {
    type: "finish",
    values: ["matte", "glossy"]
  }
];

// iterate through each variantSection and create objects like {"type": "frame", "value": "black"}
var sections = variantSections.map(variant => {
	return variant.values.map(val => ({type: variant.type, value: val}))
});

// then iterate through the two resulting arrays of objects, combining each into the attributes object you want
var results = [];
for (var i = 0; i < sections[0].length; i++) {
	for (var j = 0; j < sections[1].length; j++) {
		results.push({attributes: [sections[0][i], sections[1][j]]});
	}
}

console.log(JSON.parse(JSON.stringify(results)));

1 Comment

Hi @Nick G, thanks for the reply! I really appreciate it. However, Nina Scholz answered a few mins before you. Hence, I accepted his answer. Thanks once again!

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.