Reputation: 2675
I have an object where it can contain a duplicate and/or a falsy value. I want to compose an array of objects based on that and add a new boolean property based on the check for case-insensitive values.
This is what I have:
const obj = {
a: 'A',
b: 'B',
c: 'C',
d: 'c',
e: 'E',
f: ''
}
console.log(Object.keys(obj).map(i => {
return {
key: i,
isDuplicateOrFalsy: _.filter(
Object.values(obj),
j =>
_.trimEnd(_.toLower(j)) ===
_.trimEnd(
_.toLower(
obj[i]
)
)
).length > 1 ||
!_.every(
Object.values(obj),
Boolean
)
}
}))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"></script>
Expected Output:
[{
isDuplicateOrFalsy: false,
key: "a"
}, {
isDuplicateOrFalsy: false,
key: "b"
}, {
isDuplicateOrFalsy: true,
key: "c"
}, {
isDuplicateOrFalsy: true,
key: "d"
}, {
isDuplicateOrFalsy: false,
key: "e"
}, {
isDuplicateOrFalsy: true,
key: "f"
}]
Please advice.
Upvotes: 2
Views: 169
Reputation: 2188
A short, and more human readable.
const obj = {
a: 'A',
b: 'B',
c: 'C',
d: 'c',
e: 'E',
f: ''
}
// Object map number of occurance of each value. { a: 1, b: 1, c: 2, d: 1 }
const valuesOccurance = _.mapValues(_.groupBy(obj, _.lowerCase), occurances => occurances.length);
// function to check duplicate
const isDuplicate = value => valuesOccurance[_.lowerCase(value)] > 1;
// function to check falsy value
const isFalsy = value => !value;
const result = _.map(obj, (value, key) => {
return {
isDuplicateOrFalsy: isFalsy(value) || isDuplicate(value),
key,
};
});
console.log({ result })
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"></script>
Upvotes: 1
Reputation: 193358
Convert the object to entries of [key, value]
with _.toPairs()
, and group them by the lower case version of the value. Flat map the groups, and map each entry in the group back to an object. Any item within a group with length greater than 1 is a duplicate. Merge the objects, and get the items in the correct order using _.at()
:
const fn = obj => _.at(
_.merge(..._.flatMap(
_.groupBy(_.toPairs(obj), ([, v]) => _.lowerCase(v)),
group => group.map(([key, v]) => ( { [key]:{
key,
isDuplicateOrFalsy: group.length > 1 || _.isEmpty(_.trim(v))
}}))
)),
_.keys(obj)
)
const obj = {"a":"A","b":"B","c":"C","d":"C","e":"E","f":"","g":"c"}
const result = fn(obj)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"></script>
Upvotes: 2
Reputation: 156
const obj = {
a: 'A',
b: 'B',
c: 'C',
d: 'c',
e: 'E',
f: ''
};
const isDuplicateOrFalsyByValue = Object
.values(obj)
.reduce(
(result, value) => {
const caseInsensetiveValue = value.toLowerCase();
result[caseInsensetiveValue] = result[caseInsensetiveValue] === undefined
/*
* If `caseInsensetiveValue` is a falsy value,
then set `isDuplicateOrFalsy` to `true`
* Otherwise set it to `false`
*/
? !caseInsensetiveValue
/*
* If result[caseInsensetiveValue] is `true` (we had a falsy value),
then this `true` won't hurt
* Otherwise we have a duplicate at this point
and should set it to `true` as well.
*/
: true;
return result;
},
{},
);
const keysWithDuplicationOrFalsyInfo = Object
.entries(obj)
.reduce(
(result, [key, value]) => [
...result,
{
isDuplicateOrFalsy: isDuplicateOrFalsyByValue[value.toLowerCase()],
key,
},
],
[],
);
console.log('keysWithDuplicationOrFalsyInfo');
console.log(keysWithDuplicationOrFalsyInfo);
Upvotes: 1
Reputation: 4381
Solution does not contain unnecessary cycles:
const obj = {
a: 'A',
b: 'B',
c: 'C',
d: 'C',
e: 'E',
f: ''
}
// make array [ [key, value], ... ] and sort by values
values = Object.entries(obj).sort((a,b) => a[1] > b[1])
result = values.map((e,i, arr) => {
const [key, value] = e;
const last = values.length -1; // last index
let isDuplicateOrFalsy = false;
// true conditions = dublicates are near
if (!value) isDuplicateOrFalsy = true; // falsy check
else if (i > 0 && i < last // for middle
&& (arr[i-1][1] === value || arr[i+1][1] === value)) isDuplicateOrFalsy = true;
else if (i === 0 && arr[1][1] === value) isDuplicateOrFalsy = true; // for first
else if (i === last && arr[last-1][1] === value) isDuplicateOrFalsy = true; // for last
return {
key,
isDuplicateOrFalsy
}
})
console.log(result)
Upvotes: 1
Reputation: 25648
You could do something similar to this:
const obj = { a: 'A', b: 'B', c: 'C', d: 'C', e: 'E', f: '' };
const res = Object.entries(obj)
.map(([key, val], i, arr) => ({
key,
isDuplicateOrFalsy: !val ||
arr.some(([k, v], j) =>
j !== i && v.toLowerCase().trim() === val.toLowerCase().trim()
)
}));
console.log(res);
Upvotes: 1