Just to clarify this is what I mean by "inverted map":
const foo =
{ "a": 10
, "b": 20
};
const foo_inverted =
{ "10": "a"
, "20": "b"
};
I have this object representing a file:
const file =
{ id: 100
, tags: [20, 30]
};
Given a list of files I need to build a map that allows me to find all files with a given tag.
From this:
const files =
[ { id: 100
, tags: [20, 30]
}
, { id: 200
, tags: [20, 40]
}
];
To that:
{ "20": { "100": 1, "200": 1 }
, "30": { "100": 1 }
, "40": { "200": 1 }
}
I ended up with this code which does the job:
const tag_file = (tag_id, file_id) => ({[tag_id]: {[file_id]: 1}});
const mergeDeepAll = reduce(mergeDeepRight, {});
const tag_map = compose(mergeDeepAll, lift(tag_file));
const tags_map = compose(mergeDeepAll, map(({id, tags}) => tag_map(tags, [id])));
tags_map(files);
//=> { "20": { "100": 1, "200": 1 }
//=> , "30": { "100": 1 }
//=> , "40": { "200": 1 }
//=> }
Question: am I missing any functional programming concepts that would have allowed me to express this better?
Create an a function that generates pairs [tag, id]
for each object, using a Array.map()
( idByTags
). Using R.chain convert all objects to such pairs and flatten them. Group by the tag (R.head), and then map the object (R.mapObjIndexed) and count by the id (R.last):
const { pipe, chain, groupBy, head, mapObjIndexed, countBy, last } = R const idByTags = ({ id, tags }) => tags.map(tag => [tag, id]) const fn = pipe( chain(idByTags), groupBy(head), mapObjIndexed(countBy(last)) ) const files = [{"id":100,"tags":[20,30]},{"id":200,"tags":[20,40]}] const result = fn(files) console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script>
not sure why you would need ramda, can do it with reduce and forEach
const files = [{ id: 100, tags: [20, 30] }, { id: 200, tags: [20, 40] }]; // loop over the array to make an object const result = files.reduce((obj, file) => { // loop over the tags file.tags.forEach( tag => obj[tag]? // have we seen the tag? obj[tag].push(file.id): // yes obj[tag] = [file.id] // no ) return obj // return the object for reduce }, {}) console.log(result)
AFTER YOUR EDIT
const files = [{ id: 100, tags: [20, 30] }, { id: 200, tags: [20, 40] }]; // loop over the array to make an object const result = files.reduce((obj, file) => { // loop over the tags file.tags.forEach( tag => { obj[tag] = obj[tag] || {} // have we seen the tag? obj[tag][file.id] = 1 // }) return obj // return the object for reduce }, {}) console.log(result)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.