Reputation: 910
There are 2 arrays of objects, the first one is
const blocks = [
{ id: 1 },
{ id: 2 },
{ id: 3 },
]
and the second one is
const containers = [
{ block: { id: 1 } },
{ block: { id: 2 } },
{ block: { id: 3 } },
]
I want to take blocks
array, take each object from that and find if containers
array has block with such id. So if at least one id not found then I want to break loop and return false, otherwise if all id's found return true.
I've tried to implement this with .some()
function but I couldn't break loop when id is not found.
I would appreciate if you advise Ramda way to mplement this.
Thank you.
Upvotes: 1
Views: 3398
Reputation: 18515
You can achieve this with JS/Lodash/Ramda almost same exact way.
JS/Lodash having the same exact methods for every
and some
and in Ramda with all
and any
:
const blocks = [{ id: 1 },{ id: 2 },{ id: 3 }]
const containers = [{ block: { id: 1 } },{ block: { id: 2 } },{ block: { id: 3 } }]
const blocks2 = [{ id: 1 },{ id: 2 },{ id: 3 }]
const containers2 = [{ block: { id: 4 } },{ block: { id: 2 } },{ block: { id: 3 } }]
let hasAllBlocks = (blks, conts) =>
blks.every(b => conts.some(c => c.block.id === b.id))
let hasAllBlocksLD = (blks, conts) =>
_.every(blks, b => _.some(conts, c => c.block.id === b.id))
let hasAllBlocksR = (blks, conts) =>
R.all(b => R.any(c => c.block.id === b.id, conts), blks)
console.log(hasAllBlocks(blocks, containers)) // true
console.log(hasAllBlocks(blocks2, containers2)) // false
console.log(hasAllBlocksLD(blocks, containers)) // true
console.log(hasAllBlocksLD(blocks2, containers2)) // false
console.log(hasAllBlocksR(blocks, containers)) // true
console.log(hasAllBlocksR(blocks2, containers2)) // false
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
Upvotes: 0
Reputation: 50797
There is no particular Ramda WayTM. Ramda is a library, a toolkit, or in Underscore's description, a toolbelt. It is built to make a certain style of coding easier to read and write in JS. But it is not meant to dictate at all how you write your code.
Ramda's biggest goal is to make it easier to build applications through composing functions, ensuring such FP goodies as immutability and referential transparency.
So for this problem, I might start with something like the following:
const hasBlock = (containers) => {
const ids = containers .map (c => c.block.id)
return (block) => ids .includes (block.id)
}
const allContained = (containers) => (blocks) =>
blocks .every (hasBlock (containers) )
That latter function can be quickly rewritten using Ramda to
const allContained = (containers) => (blocks) =>
all(hasBlock(containers), blocks)
which simplifies to
const allContained = (containers) => all(hasBlock(containers))
and from there to the elegant:
const allContained = compose (all, hasBlock)
But I don't see any straightforward simplifications of hasBlock
. I might on some days write it as
const hasBlock = (containers, ids = containers .map (c => c.block.id) ) =>
(block) => ids .includes (block.id)
but that's only to satisfy some internal craving for single-expression function bodies, and not for any really good reason. It doesn't make the code any cleaner, and for some readers might make it more obscure.
So here is where I end up:
const hasBlock = (containers) => {
const ids = containers .map (c => c.block.id)
return (block) => ids .includes (block.id)
}
const allContained = compose (all, hasBlock)
const containers = [{block: {id: 1}}, {block: {id: 2}}, {block: {id: 4}}]
console .log (
allContained (containers) ([{id: 1}, {id: 2}, {id: 3}]), //=> false
allContained (containers) ([{id: 1}, {id: 2}, {id: 4}]), //=> true
allContained (containers) ([{id: 4}, {id: 1}]), //=> true
allContained (containers) ([{id: 42}]), //=> false
)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script><script>
const {compose, all} = R </script>
Upvotes: 0
Reputation: 1729
You can do this using R.differenceWith
:
const blocks = [
{ id: 1 },
{ id: 2 },
{ id: 3 },
];
const containers = [
{ block: { id: 1 } },
{ block: { id: 2 } },
{ block: { id: 4 } },
];
const diff = R.differenceWith((x,y) => x.id === y.block.id);
const mismatch = diff(blocks, containers).length > 0;
console.log(mismatch);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
Upvotes: 1
Reputation: 36574
You can use the equals()
method.
const blocks = [
{ id: 1 },
{ id: 2 },
{ id: 3 },
]
const containers = [
{ block: { id: 1 } },
{ block: { id: 2 } },
{ block: { id: 3 } },
]
console.log(R.equals(containers.map(x => x.block.id),blocks.map(x => x.id)))
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
Upvotes: 0
Reputation: 386604
In a non ramda way, you could compare each object with the other items and use a deep check.
const
deep = id => o =>
o && typeof o === 'object' && (o.id === id || Object.values(o).some(deep(id))),
compare = (source, target) => source.every(({ id }) => target.some(deep(id))),
blocks = [ { id: 1 }, { id: 2 }, { id: 3 }],
containers = [{ block: { id: 1 } }, { block: { id: 2 } }, { block: { id: 3 } }]
console.log(compare(blocks, containers));
Upvotes: 0