I've got this type of dataset :
[
{
CODMAT: '86 ',
LIBMAT: 'Chariot N.50 Damien ',
CODCAR: 'I050DCHE ',
ZONLST: 'A',
ALLLST: 1,
CIRMAT1: 'AUA',
CIRMAT2: 'SUC',
CIRMAT3: 'SAL',
CIRMAT4: 'AU3',
CIRMAT5: ' ',
CIRMAT6: ' '
},
{
...
}
]
I would like to concatenate all the 'CIRMAT' data and delete these which are empty, like this :
{
CODMAT: '86 ',
LIBMAT: 'Chariot N.50 Damien ',
CODCAR: 'I050DCHE ',
ZONLST: 'A',
ALLLST: 1,
CIRMAT: ['AUA','SUC','SAL','AU3']
}
Thanks for your help
CodePudding user response:
You can use Object.entries()
, map()
and reduce()
together to achieve what you want.
Checking for an empty string happens by using trim()
which removes leading and trailing whitespace from the string and then checking the length of the string.
const input = [
{
CODMAT: '86 ',
LIBMAT: 'Chariot N.50 Damien ',
CODCAR: 'I050DCHE ',
ZONLST: 'A',
ALLLST: 1,
CIRMAT1: 'AUA',
CIRMAT2: 'SUC',
CIRMAT3: 'SAL',
CIRMAT4: 'AU3',
CIRMAT5: ' ',
CIRMAT6: ' '
},
]
const output = input.map(item => (
Object.entries(item).reduce((newObj, [key, value]) => {
if(key.startsWith("CIRMAT") && typeof value === "string"){
// ignore values that are "empty"
if(value.trim().length === 0) return newObj;
if(!newObj.CIRMAT) newObj.CIRMAT = [value];
else newObj.CIRMAT.push(value);
}
else{
// just assign the same key the same value
newObj[key] = value;
}
return newObj;
}, {})
))
console.log(output);
.as-console-wrapper { max-height: 100% !important; top: 0; }
map()
is required to map each value in theinput
array 1:1 to a value in theoutput
array.reduce()
will do the transformation of a single item within the array. If thekey
starts withCIRMAT
we need to check whether we already have aCIRMAT
property on our working objectnewObj
. If we have not, this is the firstCIRMATx
property and we need to create an array containing thevalue
. If we already have an array and just needpush()
the newvalue
to it. In case the key does not start withCIRMAT
we just add thevalue
andkey
to our working objectnewObj
without any changes.
CodePudding user response:
This should work :
const data = [
{
CODMAT: '86 ',
LIBMAT: 'Chariot N.50 Damien ',
CODCAR: 'I050DCHE ',
ZONLST: 'A',
ALLLST: 1,
CIRMAT1: 'AUA',
CIRMAT2: 'SUC',
CIRMAT3: 'SAL',
CIRMAT4: 'AU3',
CIRMAT5: ' ',
CIRMAT6: ' '
},
]
const output = input.map(item => (
Object.entries(item).reduce((formatted, [key, value]) => {
if(key.startsWith("CIRMAT") && typeof value === "string"){
if(value.trim().length === 0) return formatted;
if(!formated.CIRMAT) formatted.CIRMAT = [value];
else formatted.CIRMAT.push(value);
}
else{
formatted[key] = value;
}
return formatted;
}, {})
))
CodePudding user response:
An approach which covers the naming schema of any to be merged key
/property name generically needs to go through all of an item's entries (key-value pairs) where it would separate each key
into its digit-less normalized property name and its digit only suffix (the trailing number) part. Then it would merge/collect only entries which feature both, the new key
and the to be discarded number
where in addition the value
is not empty (or just a whitespace sequence).
Thus one might use ...
a regex like ...
/^(\D )(\d )?$/
... which matches the pattern of a digit-less leading string and a digit-only trailing string where both substrings are being captured.Array.prototype.map
in order to create a new array of changed/merged items.Object.entries
in order to get the key-value pairs of each to be mapped array item.Array.prototype.reduce
in order to process (merge and/or collect) each entry of the to be mapped array item.
function mergeEquallyNamedButNumberedEntries(item) {
const regXNumberedKey = /^(\D )(\d )?$/;
return Object
.entries(item)
.reduce((merger, [key, value]) => {
const [
match,
mergerKey = null,
trailingNumber = null,
] =
key.match(regXNumberedKey) ?? [];
if (mergerKey !== null) {
if (trailingNumber !== null) {
if (String(value ?? null).trim() !== '') {
(merger[mergerKey] ??= []).push(value);
}
} else {
merger[mergerKey] = value;
}
}
return merger;
}, {});
}
const sampleData = [{
CODMAT: '86 ',
LIBMAT: 'Chariot N.50 Damien ',
CODCAR: 'I050DCHE ',
ZONLST: 'A',
ALLLST: 1,
CIRMAT1: 'AUA',
CIRMAT2: 'SUC',
CIRMAT3: 'SAL',
CIRMAT4: 'AU3',
CIRMAT5: ' ',
CIRMAT6: ' '
}, {
foo: 567,
bar: 'baz',
baz99: ' ',
baz88: ' ',
baz77: '',
biz11: '',
biz22: ' ',
biz33: 'foo',
}];
const result = sampleData
.map(mergeEquallyNamedButNumberedEntries);
console.log({ result, sampleData });
.as-console-wrapper { min-height: 100%!important; top: 0; }
CodePudding user response:
You can follow the below approach to solve this:
// obj is an example (key, value) pair array,
// you should pass your desired one inside Solve function
var obj = {
CODMAT: "86 ",
LIBMAT: "Chariot N.50 Damien ",
CODCAR: "I050DCHE ",
ZONLST: "A",
ALLLST: 1,
CIRMAT1: "AUA",
CIRMAT2: "SUC",
CIRMAT3: "SAL",
CIRMAT4: "AU3",
CIRMAT5: " ",
CIRMAT6: " ",
};
function Solve(obj) {
var data = [];
var res = [];
for (const [key, value] of Object.entries(obj)) {
if (key.search("CIRMAT") !== -1) {
if (value.trim().length > 0) {
data.push(value);
}
} else {
res[key] = value;
}
}
res["CIRMAT"] = data;
return res;
}
var ret_val = Solve(obj);
// Console Print the output (optional / debug)
console.log(ret_val);
After getting ret_val, assign it inside your desired array. Hope this solution answers your question.