Reputation: 876
Suppose, I have an array which contains value [1,1,2,2,3,3]. I want to group all the distinct number in this array so I should have the result like this { "0": [1,2,3], "1": [1,2,3] }
So here what I have tried. The inital value actually start at 1-99 so if I % by 10 all will have something like [0,..,9,0,...,9] and after that I don't know what to do next.
const test = compose(
groupBy(i => ...),
map(i => i % 10),
range
)(1, 10*10);
this worked for me
const test = compose(
mapObjIndexed((value,key,obj) => value.map((numb,index) => obj[index][key])),
groupBy(i => i),
map(i => i % 10),
range
)(1, 10*10)
Upvotes: 1
Views: 352
Reputation: 50797
The idea customcommander presents of using transpose
makes this pretty easy. Two further steps seem to get you fully to your goal... if I understand that goal correctly. First, we can replace groupWith(equals)
with groupBy(identity)
followed by values
; this means it no longer matters whether the input is sorted. Second, if you really want the {0: [1, 2, 3], 1: [1, 2, 3]}
output rather than the more common [[1, 2, 3], [1, 2, 3]]
, we can end with a toPairs
/fromPairs
shuffle (equivalently, Object.entries
/Object.fromEntries
.) On a plain object, that would be a no-op. But on an array, it converts it to an object with such integer keys.
const group = pipe (
groupBy (identity),
values,
transpose,
toPairs,
fromPairs
)
console .log (group ([1, 1, 2, 2, 3, 3]))
console .log (group ([1, 5, 1, 2, 4, 2, 3, 3, 1, 2, 1, 3, 1, 1, 3, 2, 1, 4]))
.as-console-wrapper {min-height: 100% !important; top: 0}
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script>
<script> const {pipe, groupBy, identity, values, transpose, toPairs, fromPairs} = R </script>
So this is my understanding of what you're trying to achieve. Please let me know if this is wrong:
The output is an object with keys being the small non-negative integers (0
, 1
, 2
, ...). Key 0
has the unique values from the original input. Key 1
has the unique values remaining after you remove one of each element of key 0
from the input. Key 2
has the unique values remaining after you remove one of each element of key 0
from the input and then one of each element of key 1
from the remainder, and so forth.
Note that although the results have the elements sorted, that's a happy accident, based on the strange key-sorting algorithm for small integers in JS. If you were to replace the 1
's by a
's, the 2
's by b
's and so forth in the second example, the results would be sorted differently:
console .log (group (['a', 'e', 'a', 'b', 'd', 'b', 'c', 'c', 'a', 'b', 'a', 'c', 'a', 'a', 'c', 'b', 'a', 'd']))
//=> {"0":["a","e","b","d","c"],"1":["a","b","d","c"],"2":["a","b","c"],"3":["a","b","c"],"4":["a"],"5":["a"],"6":["a"]}
If this is an issue, you could end the pipeline with map (sortBy (identity))
.
Upvotes: 2
Reputation: 18901
Assuming your list is sorted, it could be as simple as:
This may be an oversimplification of your problem at hand but this solution may be enough to get you started
const group = compose(transpose, groupWith(equals));
console.log(group([1,1,2,2,3,3]));
//=> [[1,2,3],[1,2,3]]
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.min.js"></script>
<script>const {compose, equals, groupWith, transpose} = R;</script>
What's happening here?
First groupWith(equals)
creates sequences of similar adjacent numbers (which is why the list must be sorted)
groupWith(equals, [1,1,2,2,3,3]);
//=> [[1,1],[2,2],[3,3]])
Then transpose
will create from x lists of n length, n lists of x length:
transpose([[1,1],[2,2],[3,3]])
//=> [[1,2,3],[1,2,3]]
We had 3 lists of 2 items, we now have 2 lists of 3 items.
It should now be easy to produce a map from it if necessary.
Upvotes: 2
Reputation: 386634
You could take an object which keeps the index for the target of the same value.
This approach fills the first arrays first.
var data = [1, 1, 2, 2, 3, 3],
indices = {},
result = {};
for (let value of data) {
if (!indices[value]) indices[value] = 0;
const index = indices[value]++;
if (!result[index]) result[index] = [];
result[index].push(value);
}
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 1