Remove several array elements by index and store removed elements - javascript

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

Related

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

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>

How to deal with adding and removing items in pagination (infinite scroll)

I have REST API endpoint that accepts page, limit (page size) and returns (for simplicity) sorted letters of alphabet (A, B, C, ... Z). Example call of this endpoint is:
let items = await api.items.get({ page: 0, size: 3 })
// items = ["A", "B", "C"]
Now let's say I have implemented infinite scroll and when user scrolls at the of the area, I want to load another 3 items:
const newItems = await api.items.get({ page: 1, size: 3 })
items = [...items, ...newItems]
// items = ["A", "B", "C", "D", "E", "F"]
Everything is fine, however what if user deletes some items, eg. "B" and "D"?
// items = ["A", "C", "E", "F"]
How can I fetch another page of 3 items from correct offset?
const newItems = await api.items.get({ page: 2, size: 3 })
items = [...items, ...newItems]
// items = ["A", "C", "E", "F", "I", "J", "K"] - "G" and "H" has been skipped
Are there any common techniques for this? Unfortunately, I can't modify the API, so I have to use page and size only.

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

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

How do I use an array of indices to alter a specific item in a multi-dimensional object of unknown depth? [duplicate]

This question already has answers here:
Access nested objects via array of property names
(2 answers)
Closed 6 years ago.
Imagine I have an array, which looks like:
const x = ["a", "b", "c", "d"]
I wish to use it in order to navigate an object that I don't know the structure of, like:
const y = {
"a": {
"b": {
"c": {
"d": "Value I require"
}
},
"f": ["g", "h"]
},
"e": null
}
However, my issue is that I don't know how deep y will be, or how many indices are in the array x. How do I do the following:
let someVariable = {"prefilled": "data"}
someVariable[x[0]][x[1]][x[2]][x[3]] = y[x[0]][x[1]][x[2]][x[3]]
In a way which is neither specific to the length of x, the depth of y (and also preferably isn't my current solution, which is a case statement upto a depth of 6)? For this simplified case, someVariable should hopefully look as follows:
{
"prefilled": "data",
"a": {
"b": {
"c": {
"d": "Value I require"
}
}
}
}
I would either use a tool like Lodash's _.get or implement something similar that can navigate an object:
let _ = require('lodash');
const x = ["a", "b", "c", "d"]
_.get(object, x.join('.'))
You could iterate the array and walk the object.
const getValue = (object, path) => path.reduce((o, k) => (o || {})[k], object),
y = { a: { b: { c: { d: "Value I require" } }, f: ["g", "h"] }, e: null },
x = ["a", "b", "c", "d"]
console.log(getValue(y, x));

Categories