Как построить инвертированную карту из списка «один ко многим» с функциональным программированием в JavaScript? - PullRequest
1 голос
/ 17 апреля 2020

Просто чтобы уточнить, что я имею в виду под "перевернутой картой":

const foo =
  { "a": 10
  , "b": 20
  };

const foo_inverted =
  { "10": "a"
  , "20": "b"
  };

У меня есть этот объект, представляющий файл:

const file =
  { id: 100
  , tags: [20, 30]
  };

Имеется список Файлы, которые мне нужны, чтобы построить карту, которая позволит мне найти все файлы с данным тегом.

Из этого:

const files =
  [ { id: 100
    , tags: [20, 30]
    }
  , { id: 200
    , tags: [20, 40]
    }
  ];

Для этого:

{ "20": { "100": 1, "200": 1 }
, "30": { "100": 1 }
, "40": { "200": 1 }
}

I в конечном итоге с этим кодом, который выполняет работу:

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 }
//=> }

Вопрос: я пропустил какие-либо концепции функционального программирования, которые позволили бы мне express это лучше?

Ответы [ 2 ]

2 голосов
/ 17 апреля 2020

Создайте функцию, которая генерирует пары [tag, id] для каждого объекта, используя Array.map() (idByTags). Используя R.chain, преобразуйте все объекты в такие пары и сгладьте их. Сгруппируйте по тегу (R.head), затем сопоставьте объект (R.mapObjIndexed) и посчитайте по идентификатору (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>
0 голосов
/ 17 апреля 2020

не знаю, зачем вам нужна рамда, можете сделать это с помощью Reduce и 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)

ПОСЛЕ ВАШЕГО РЕДАКТИРОВАНИЯ

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)
...