mikeD
mikeD

Reputation: 229

How to combine two array, but take care for no same elements

I have a simple question. Before I have look around, but the answers I find, was mostly for another situation.

I have two arrays with css-properties

old=['font-size: 12px;','color: 12px;','border-left: 1px solid red;'];
new=['font-size: 20px;','border-left: 1px solid green;','left:20px;'];

How can I combine this both arrays to have at the end an array which contains only unique styles with the properties from the "new" array if there is something change to the old ones?

In the example above, I want to have this result

result=['font-size: 20px;','color: 12px;','border-left: 1px solid green;','left:20px;'];

At the first time, I try to make a loop through the old elements, split the items at the ":" but then I see a problem about the names of the styles. If I check if "left" is inside a string it will return true on "left" but also on every other style-names which contains "left" for example margin-left, padding-left...

How I can solve it in the easiest way?

Thanks a lot.

Upvotes: 0

Views: 63

Answers (3)

jo_va
jo_va

Reputation: 13963

Use can use Object.Values(), Array.reduce() and String.match():

const css1 = ['font-size: 12px;','color: 12px;','border-left: 1px solid red;'];
const css2 = ['font-size: 20px;','border-left: 1px solid green;','left:20px;'];

const merged =
  Object.values(
    [...css1, ...css2].reduce(
      (acc, x) => (acc[x.match(/(.*)\s*:/)[1]] = x, acc), {}));

console.log(merged)

Upvotes: 1

trincot
trincot

Reputation: 350272

When you have support for Object.fromEntries, then:

function mergeCss(...args) {
    return Object.entries(
        Object.fromEntries(args.flatMap(a => a.map(a => a.match(/^[^:\s]*|[^:\s].+$/g))))
    ).map(arg => arg.join(": "));
}

const result = mergeCss(['font-size: 12px;','color: 12px;','border-left: 1px solid red;'],
                        ['font-size: 20px;','border-left: 1px solid green;','left:20px;']);

console.log(result);

You can pass more than two arrays to the above function.

Polyfill for Object.fromEntries:

Object.fromEntries = arr => 
    Object.assign({}, ...Array.from(arr, ([k, v]) => ({[k]: v}) ));

Upvotes: 2

CertainPerformance
CertainPerformance

Reputation: 370759

You might create a single array from the two (with the new items at the end) then reduce into an object indexed by the substring that comes before the : in the strings, and then get the object's entries:

const old = ['font-size: 12px;', 'color: 12px;', 'border-left: 1px solid red;'];
const newArr = ['font-size: 20px;', 'border-left: 1px solid green;', 'left:20px;'];
const resultObj = [...old, ...newArr].reduce((a, str) => {
  const [key, val] = str.split(/: ?/);
  a[key] = val;
  return a;
}, {});
const result = Object.entries(resultObj).map(([key, value]) => `${key}: ${value}`);
console.log(result);

Note that new is a reserved word - it can't be a variable name.

Upvotes: 5

Related Questions