Ramda JS partition array into multiple sub-arrays based on indices - javascript

I would like to take an array and split it into a dictionary of sub-arrays based on another array of indices:
const arr = ["A", "B", "C", "D", "E"];
const indices = [0, 0, 1, 0, 3];
// Would like to do something like this:
R.split(indices, array) // { "0": ["A", "B", "D"], "1": ["C"], "3": ["E"] }
Is there an elegant way to do this in Ramda?

Use R.zip combine the arrays to an array of values/indices pairs. Group by the indices, and then take only the values from the pairs:
const { pipe, zip, groupBy, last, map, head } = R
const fn = pipe(
zip, // combine the arrays to an array of value/indice pairs
groupBy(last), // group by the indices
map(map(head)) // take only the values from the pairs
)
const arr = ["A", "B", "C", "D", "E"]
const indices = [0, 0, 1, 0, 3]
const result = fn(arr, indices)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.28.0/ramda.min.js" integrity="sha512-t0vPcE8ynwIFovsylwUuLPIbdhDj6fav2prN9fEu/VYBupsmrmk9x43Hvnt+Mgn2h5YPSJOk7PMo9zIeGedD1A==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

Related

How to create permutations of tuple-like list where identical integer pairs are not permuted

I have this array of arrays, where the inner arrays are uniformly structured (“tuple-like”) with a unique ID (a string) and a non-unique integer:
[
["A",2],
["B",1],
["C",1]
]
I need the JavaScript function to create the list of permutations below, that does not permute tuples with the same integer value:
[
["A", "B", "C"],
["B", "A", "C"],
["B", "C", "A"]
]
Quoting user pilchard in the comments below, I'm trying to permute “by the second index and avoid duplicates”.
The list should therefore not include these permutations:
[
["A", "C", "B"], // integers same as in ["A", "B", "C"]
["C", "A", "B"], // integers same as in ["B", "A", "C"]
["C", "B", "A"] // integers same as in ["B", "C", "A"]
]
Also, it is preferable to avoid “movement” inside the array. Therefore, ["A", "B", "C"] is a better permutation than ["A", "C", "B"]
In the simplest scenario, the input could be this:
[
["A",1],
["B",1],
["C",1],
["D",1]
]
The result should simply be 1 permutation, as opposed to the 24 that is the result when also permuting identical integers:
[
["A", "B", "C", "D"]
]
Again, “movement” inside the array should be avoided, so ["A", "B", "C", "D"] is the preferred alternative.
Instead of operating on an array of characters, operate on an array of groups of characters. You can take any of these solutions, and instead of removing the chosen character from the input to put it into the output, remove the first character of the chosen group and remove the group only when it's empty.
function groupPermutations(groups) {
if (!groups.length) return [[]];
return groups.flatMap((group, i) => {
// assert(group.length > 0)
const [val, ...rest] = group;
const remaining = rest.length
? [...groups.slice(0,i), rest, ...groups.slice(i+1)]
: [...groups.slice(0,i), ...groups.slice(i+1)];
return groupPermutations(remaining).map(p => [val, ...p]);
});
}
console.log(groupPermutations(["A", "BC"]));
console.log(groupPermutations(["ABCD"]));
Now you only need a trivial conversion of your tuple input format to the grouping:
const pairs = [
["A",2],
["B",1],
["C",1],
];
const byInteger = new Map();
for (const [val, key] of pairs) {
if (!byInteger.has(key)) byInteger.set(key, []);
byInteger.get(key).push(val);
}
const groups = Array.from(byInteger.values());
console.log(groupPermutations(groups));

Remove several array elements by index and store removed elements

How can I remove multiple items by index and save the removed items. I get the currently selected values from a ListBox (e.g.selectedValues = [1, 4, 2]) and have two arrays actives availables. I try to move the selected elements in an efficient way.
That's how I would solve this:
var actives = [ "a", "d", "k", "e"]
var availables = [ "m", "o", "v" ]
var selectedValues = [3, 1]
var elementsToMove = []
selectedValues.forEach(i => {
elementsToMove.push(actives[i])
})
actives = actives.filter(item => !elementsToMove.includes(item))
availables = availables.concat(elementsToMove);
console.log(actives);
console.log(availables);
Expected output:
actives = [ "a", "k" ]
availables = [ "m", "o", "v", "e", "d"]
Note: The length of the arrays can be very large.
A .filter with an .includes inside is O(n ^ 2). For very large inputs, this could be an issue. Consider converting the elementsToMove into a Set instead, turning the overall computational complexity to O(n). You can also construct the elementsToMove array much more concisely by using .map instead of forEach followed by push:
var actives = [ "a", "d", "k", "e"]
var availables = [ "m", "o", "v" ]
var selectedValues = [3, 1];
const elementsToMove = selectedValues.map(i => actives[i]);
const elementsToMoveSet = new Set(elementsToMove);
actives = actives.filter(item => !elementsToMoveSet.has(item))
availables = availables.concat(elementsToMove);
console.log(actives);
console.log(availables);
You could take a single loop and psuh the spliced elements to the other array.
var actives = [ "a", "d", "k", "e"],
availables = [ "m", "o", "v" ],
selectedValues = [3, 1];
selectedValues.forEach(i => availables.push(...actives.splice(i, 1)));
console.log(actives);
console.log(availables);

convert array of string to array of object - javascript [duplicate]

This question already has an answer here:
Convert array of strings to objects and assign specific key
(1 answer)
Closed 3 years ago.
I have an array of strings.
["A", "B", "C", "D"]
How can I add a key to the array, to make it object.
Like this, to an array on object.
[{ id: "A" }, { id: "B" }, { id: "C" }]
I tried the following:
const newArray = this.myArray.map(function(item) {
return 'id:' + item;
});
This does not work for me though.
You're on the right track. You're returning a string. You must return an object
const newArray = this.myArray.map(function(item) {
return {'id': item};
});
Inside the map() event handler function you are returning a string not an object. You should form the object and return that.
You can also achieve that in a single line with arrow function (=>):
const myArray = ["A", "B", "C", "D"];
const newArray = myArray.map(i => ({id: i}));
console.log(newArray);
Just return an object instead of a string:
const arr = ["A", "B", "C", "D"];
const res = arr.map(id => ({id}));
console.log(res);
This is a good use-case for Array.prototype.map:
const stringArr = ["A", "B", "C", "D"];
const objArr = stringArr.map(id => ({ id }));
console.log(objArr);

Javascript create array with fixed value but matching column amount from another array

I have an array which is built from data dynamically, so it can change.
It's basically this:
["t1", "something", "bird", "dog", "cow", "fish"]
What I need to do is to count how many of them there are and create another array with the same amount of columns but all with the value of 1.
For example, if the array is:
["bird", "dog", "cow", "fish"]
then it creates an array of:
[1, 1, 1, 1]
If the array is:
["bird", "fish"]
then it creates an array of:
[1, 1]
How can I do this?
You can use the Array.prototype.map method:
var input = ["foo", "bar", "baz"];
var mapped = input.map(function () { return 1; });
Just create a new array of equal length and use the fill function.
var myArray = ["dog","cat","monkey"];
var secondArray = new Array(myArray.length).fill(1);
// es6
var array = ["t1", "something", "bird", "dog", "cow", "fish"]
array.map(() => 1); // => [1, 1, 1, 1, 1, 1]
// if you don't care if they are strings
'1'.repeat(array.length).split(''); //=> ["1", "1", "1", "1", "1", "1"]

How to implement rxjs zip operator for array of arrays?

I have a source that gives an array of arrays. All arrays has the same number of element(s).
How can I use rxjs zip operator to transform the source array as described below so I could easily do the mapping? Thanks in advance!
var source = Rx.Observable.from([[1, 2, 3], ["a", "b", "c"], ["do", "re", "mi"]]);
// I would like to transform to:
// [[1, "a", "do"], [2, "b", "re"], [3, "c", "mi"]]
You can convert each array to an Observable, then zip:
var myArrays = [
[1, 2, 3],
['a', 'b', 'c'],
['do', 're', 'mi']
];
var myObservables = myArrays.map(xs => Rx.Observable.from(xs));
var zipped$ = Rx.Observable.zip(myObservables);
zipped$.subscribe(x => console.log(x));
Alternatively, you can forego the conversion from Array to Observable and use lodash's zip to combine the arrays:
var zipped = _.zip(...myArrays)

Categories