最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - ramda.js: obtain a set of duplicates from an array of objects using specific properties - Stack Overflow

programmeradmin0浏览0评论

Given this array, containing javascript objects (json):
Each object has a bproperty, and a u property,

(each contains additional properties I am not concerned with for this exercise).

[
    { "b": "A", "u": "F", ... },
    { "b": "M", "u": "T", ... },
    { "b": "A", "u": "F", ... },
    { "b": "M", "u": "T", ... },
    { "b": "M", "u": "T", ... },
    { "b": "X", "u": "Y", ... },
    { "b": "X", "u": "G", ... },
]

I would like to use ramda to find a set of all the duplicates. The result should look something like this.

[ 
    { "b": "A", "u":"F" },
    { "b": "M", "u":"T" } 
]

These two entries have duplicates they are repeated 2 and 3 times in the original list respectively.

edit

I have found a solution using underscore, that keeps the original array elements, and splits them perfectly into singles and duplicates. I prefer ramda.js, and underscore doesn't just give a set of duplicates - as per the question, so I am leaving the question open until someone can answer using ramda. I am moving on with underscore until the question is answered.

I have a repl that finds the unique values... as a start...

Given this array, containing javascript objects (json):
Each object has a bproperty, and a u property,

(each contains additional properties I am not concerned with for this exercise).

[
    { "b": "A", "u": "F", ... },
    { "b": "M", "u": "T", ... },
    { "b": "A", "u": "F", ... },
    { "b": "M", "u": "T", ... },
    { "b": "M", "u": "T", ... },
    { "b": "X", "u": "Y", ... },
    { "b": "X", "u": "G", ... },
]

I would like to use ramda to find a set of all the duplicates. The result should look something like this.

[ 
    { "b": "A", "u":"F" },
    { "b": "M", "u":"T" } 
]

These two entries have duplicates they are repeated 2 and 3 times in the original list respectively.

edit

I have found a solution using underscore, that keeps the original array elements, and splits them perfectly into singles and duplicates. I prefer ramda.js, and underscore doesn't just give a set of duplicates - as per the question, so I am leaving the question open until someone can answer using ramda. I am moving on with underscore until the question is answered.

I have a repl that finds the unique values... as a start...

Share Improve this question edited Sep 6, 2017 at 9:40 Jim asked Sep 5, 2017 at 17:19 JimJim 16.1k17 gold badges89 silver badges174 bronze badges 3
  • Do you want plete duplicates or only those that match on b and u? – Scott Sauyet Commented Sep 5, 2017 at 19:25
  • no, only the matching fields, "b" and "u" - though for interest - it would be nice to know. I suspect that R.equals might cater for all being equal. – Jim Commented Sep 5, 2017 at 19:55
  • 1 I have spent a whole lot more time trying to resolve this using R.head, and R.tail - have e to the conclusion that this is a m*** of a tricksy question... Trying to somehow iterate over the unique list, and remove one match from the data for each match in unique seems like the right approach... but I haven't managed to get the position correct yet. – Jim Commented Sep 6, 2017 at 12:47
Add a ment  | 

4 Answers 4

Reset to default 3

This seems overplicated and unlikely to be performant, but one options would be this:

const foo = pipe(
  project(['b', 'u']),
  reduce(
    ({results, foundOnce}, item) => contains(item, results)
      ? {results, foundOnce}
      : contains(item, foundOnce)
        ? {results: append(item, results), foundOnce}
        : {results, foundOnce: append(item, foundOnce)},
    {results: [], foundOnce: []}
  ), 
  prop('results')
)

foo(xs); //=> [{b: 'A', u: 'F'}, {b: 'M', u: 'T'}]

Perhaps this version is easier to understand, but it takes an extra iteration through the data:

const foo = pipe(
  project(['b', 'u']),
  reduce(
    ({results, foundOnce}, item) => contains(item, foundOnce)
        ? {results: append(item, results), foundOnce}
        : {results, foundOnce: append(item, foundOnce)},
    {results: [], foundOnce: []}
  ),
  prop('results'),
  uniq
)

repl here

If you don't care about looping over your data multiple times, you could something like this:

  • Create partial copies that contain only the relevant props, using pick (your own idea)
  • use groupBy with a hash function to group similar objects. (Alternatively: sort first and use groupWith(equals))
  • Get the grouped arrays using values
  • Filter out arrays with only 1 item (those are not duped...) using filter
  • Map over the results and return the first element of each array using map(head)

In code:

const containsMoreThanOne = pose(lt(1), length);
const hash = JSON.stringify; // Naive.. watch out for key-order!

const getDups = pipe(
  map(pick(["b", "u"])),
  groupBy(hash),
  values,
  filter(containsMoreThanOne),
  map(head)
);

getDups(data);

Working demo in Ramda REPL.

A more hybrid approach would be to cramp all this logic in one reducer, but it looks kind of messy to me...

const clean = pick(["b", "u"]);
const hash = JSON.stringify;
const dupReducer = hash => (acc, o) => {
    const h = hash(o);
    // Mutate internal state
    acc.done[h] = (acc.done[h] || 0) + 1;
    if (acc.done[h] === 2) acc.result.push(o);

    return acc;
  };


const getDups = (clean, hash, data) =>
  reduce(dupReducer(hash), { result: [], done: { } }, map(clean, data)).result;

getDups(clean, hash, data);

REPL

  const arr = [];
  const duplicates = [];
  const values1 =  [
  { b: 'A', u: 'F', a: 'q' },
  { b: 'M', u: 'T', a: 'q' },
  { b: 'A', u: 'F', a: 'q' },
  { b: 'M', u: 'T', a: 'q' },
  { b: 'M', u: 'T', a: 'q' },
  { b: 'X', u: 'Y', a: 'q' },
  { b: 'X', u: 'G', a: 'q' },
 ];
 values1.forEach(eachValue => {
 arr.push(values(pick(['b', 'u'], eachValue)));
 });
 arr.forEach(fish => {
 if ( indexOf(fish, arr) !== lastIndexOf(fish, arr) ) {
   duplicates.push(zipObj(['b', 'u'], fish));
 }
});

[blog]: https://ramdafunctionsexamples./ "click here for updates"

<https://ramdafunctionsexamples./>?

Not an expert with Ramda JS but I think the following should work :

var p = [
    { "b": "A", "u": "F" },
    { "b": "A", "u": "F" },
    { "b": "A", "u": "F" },
    { "b": "A", "u": "F" },
    { "b": "A", "u": "F" },
    { "b": "M", "u": "T" }
];
var dupl = n => n > 1;
R.pose(
    R.map(JSON.parse),
    R.keys,
    R.filter(dupl),
    R.countBy(String),
    R.map(JSON.stringify)
)(p)

Please let me know if it does.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论