How can this array manipulation problem be solved scalably? - javascript

I am working with JS and came across an interesting Array manipulation problem. I'm aware that the problem can be solved with a tremendous if - else if clause, but am actually looking for a more scalable answer.
I have two arrays (let's call them input and output) whose contents are related to each other. The first array contains a list of ids, and the second array is actually a response from an API (I have no power over the API) matching the ids of the input array.
Examples: If I have an input array of [1, 2, 3] I will end up with an output array of
[
{ id: 1, data: "Some data for id 1" },
{ id: 2, data: "Some data for id 2" },
{ id: 3, data: "Some data for id 3" }
]
So far so good. However, the problem arises if I have an input array like [1, 2, 2], which is possible and intentional. In this situation I end with an output array of
[
{ id: 1, data: "Some data for id 1" },
{ id: 2, data: "Some data for id 2" }
]
In the above case I would need to have the output array be of length === 3 and the third item to be a copy of the second item like so
[
{ id: 1, data: "Some data for id 1" },
{ id: 2, data: "Some data for id 2" },
{ id: 2, data: "Some data for id 2" }
]
Two more examples for clarity:
Input: [4, 4, 4], what I get:
[
{ id: 4, data: "Some data for id 4" }
]
What I need to achieve:
[
{ id: 4, data: "Some data for id 4" },
{ id: 4, data: "Some data for id 4" },
{ id: 4, data: "Some data for id 4" }
]
Last one, input: [3, 3, 7]
What I get:
[
{ id: 3, data: "Some data for id 3" },
{ id: 7, data: "Some data for id 7" }
]
What I need to achieve:
[
{ id: 3, data: "Some data for id 3" },
{ id: 3, data: "Some data for id 3" },
{ id: 7, data: "Some data for id 7" },
]
I am working with a maximum array length of three, so an if-else clause comparing lengths and values is sufficient for this, but is there a dynamic and scalable way to manipulate the output array in the intended way? I was not able to think if anything from my mind.
EDIT: I should add that the data part can be anything, not just the text I am giving here.
Thanks in advance!

The map function allows us to create new arrays from a pre-existing one.
const outputArray = inputArray.map(id => {
return {
id: id,
data: "Some data for id " + id
}
});

Related

Returning the ids from the object within the arrays

I have a multidimensional javascript array of objects that I am trying to use to simply collate the Unit id into a new array as shown below.
What is the best solution for returning the id within the inner value so I just get an array of the ids whatever I try seems to not work
[
{
units: [
{
id: 10000282,
name: "Group 1",
},
{
id: 10000340,
name: "Group 2",
},
{
id: 10000341,
name: "Group 3",
},
],
},
{
units: [
{
id: 10000334,
name: "Group 4",
},
],
},
]
Expected output - just return an array with simply the ids
e.g
ids = [ 10000282, 10000340, 10000341, 10000334 ]
Assuming that data is in variable data:
> data.map(o => o.units.map(u => u.id)).flat()
[ 10000282, 10000340, 10000341, 10000334 ]
This assumes you're in an environment where .flat() is a thing.
If that's not the case, the longer way around is
const ids = [];
data.forEach(o => {
o.units.forEach(u => {
ids.push(u.id);
});
});

Inserting array item into JS object

I have a unique situation that I'm struggling with. I have some data like this. Excuse any incorrect terms as I'm fairly new to this.
usersByName: {
"tester": {
0: {
id: 123
name: "Some Name"
data: "Some data"
},
1: {
id: 124
name: "Some Name 2"
data: "Some data 2"
},
2: {
id: 125
name: "Some Name 3"
data: "Some data 4"
},
},
"tester 2": {
0: {
id: 12
name: "Some Name"
data: "Some data"
},
1: {
id: 13
name: "Some Name 2"
data: "Some data 2"
},
}
}
I am returning a piece of data like this.
{
id: 44
name: "Some Name New"
data: "Some data New"
}
and a name like tester 2.
How can I add the new piece of data to the name I have found so the new data gets added as a third element to tester 2.
I am using react and next js so hoping to add it directly to the state if possible.
I think something like this but can't work out the obvious parts of it that are wrong
this.setState((prevState) => ({
usersByName: { // copy all other key-value pairs
newuservar: {
...prevState.usersByName.newuservar, // copy all pizza key-value pairs
X: newData,
},
},
}))
Since I see the user objects have the key start with numbers, I assume they're arrays. Try this:
// newuservar = 'tester 2';
this.setState((prevState) => ({
usersByName: {
...prevState.usersByName,
[newuservar]: prevState.usersByName[newuservar].concat(newData)
},
}))

Javascript Map a Collection

The Issue:
I'm attempting to build a simple search tool. It returns a search query by matching an id to another item with the same id. Without going into the complexities, the issue I'm having is that when my data was organized previously, the map function from javascript returned all the results perfectly. However, now that my data is structured a bit differently (a collection, I think?) ....the ids don't appear to be lining up which causes the wrong search results to show.
The function in question:
const options = this.props.itemIds.map((id) => (
<Option key={this.props.itemSearchList[id].id}>
{this.props.itemSearchList[id].name}
</Option>
));
When the data was structured like this it worked as expected:
Example of previous structure:
const items = [
{
id: 0,
name: "name 0",
tags: ['#sports', '#outdoor', '#clothing'],
},
{
id: 1,
name: "name 1",
tags: ['#sports', '#outdoor', '#clothing'],
},
{
id: 2,
name: "Name 2",
tags: ['#sports', '#outdoor', '#clothing'],
},
Now that the data is a ?collection...the map function doesn't work as anticipated and it returns improper results or none at all: I've been able to use the lodash Map function on this structure successfully in the past.
Here's a screenshot of the new data:
I believe a representative way to write out the example would be:
const newItems = [
0: {
id: 0,
name: "name here",
},
1: {
id: 1,
name: "name here",
},
]
Any recommendations for making this work or need more info? Perhaps I'm misunderstanding the issue entirely, but I believe it has to do with data structure and the map function from JS. I can see results returning, but the id's are not lining up appropriately anymore.
Here's a visual representation of the misalignment. The orange is the search input and it pulling the right result. The green is the misalignment of what it's actually showing because of the data structure and mapping (I assume).
The issue is you were using index and lining that up with id as a sort of pseudo-key which is...beyond fragile. What you should be doing is keying by id (meaing itemsshould be an object) and then having a seperate array that stores the order you want. So items would be an object keyed by id:
const items = {
1: {
id: 1,
name: "name 1",
tags: ['#sports', '#outdoor', '#clothing'],
},
2: {
id: 2,
name: "name 2",
tags: ['#sports', '#outdoor', '#clothing'],
},
9: {
id: 9,
name: "Name 9",
tags: ['#sports', '#outdoor', '#clothing'],
},
};
And then itemIds (which it appears you already have) is an array with the correct order:
const itemIds = [1,9,2];
And then they can be accessed in the right order by looping over that array, and getting the element by said key:
itemIds.map((id) => {
const item = items[id];
// do something with the item
}
Take a look at how Redux recommends normalizing state shape.
https://redux.js.org/recipes/structuring-reducers/normalizing-state-shape
What you call "collections" and "maps" are actually arrays. Now one of the arrays has the objects exactly at the position in the array that matches the id:
items[5].id === 5
Now through sorting /mutating / whatever you change the order so that the element at a certain position doesnt have that as an id:
newItems[5].id // 7 :(
That means that you cannot access the item that easy anymore, you now either have to sort the array again to bring it into order, or you search for an object with the id:
newItems.find(item => item.id === 5) // { id: 5, ... }
Or you switch over to some unsorted collections like a real Map:
const itemsMap = new Map(newItems.map(item => ([item.id, item])));
So you can get a certain item with its id as:
itemsMap.get(5) // { id: 5, ... }
... but the whole thing doesnt have to do with Array.prototype.map at all.
Here was my simple solution:
const options = [];
this.props.itemList.forEach((item) => {
if (this.props.searchResults.includes(item.id)) {
options.push(<Option key={item.id}>{item.name}</Option>);
}
});
Let me know what you think (to the group that tried to help!)

Is there a points-free way of filtering out tuples from a list by comparing their elements?

So I have some code which has a requirement of calling xprod with (input, input), similar to as follows:
const input = [
{ id: 1, data: 'a' },
{ id: 2, data: 'b' },
];
const product = xprod(input, input);
/*
[
[ { id: 1, data: 'a' }, { id: 1, data: 'a' } ],
[ { id: 1, data: 'a' }, { id: 2, data: 'b' } ],
[ { id: 2, data: 'b' }, { id: 1, data: 'a' } ],
[ { id: 2, data: 'b' }, { id: 2, data: 'b' } ],
]
*/
I'd like to filter tuples in the list above by comparing the first element of the tuples to the second element in the same tuple. In this case, to remove the tuples which contain objects which have equal ids (so the 0th and 3rd elems should be filtered out -- I know in this simplified example I could use strict equality to filter, too, but that's often not the case in the code I'm actually writing).
I know I can accomplish this pretty simply with lambdas, but since I find myself ending up with this sort of data (lists of tuples) fairly often when working with ramda, I often get stuck on trying to compare one item in a tuple to another item in the same tuple in a points free manner. And maybe that's an argument to just keep it simple and use the lambda, but I'm curious if there's a different way to do it.
Here's a link to a ramda repl containing an implementation.
One option is to simply wrap a function that expects the two arguments of the tuple with R.apply. In your example that could be a partially applied R.eqProps.
R.filter(R.apply(R.eqProps('id')), product)

Convert JSON into Array of JavaScript Objects

I got a JSON result from PHP that looks like this below. I need to convert it into an array of objects like shown at the bottom.
How can I achieve this?
What I have
Milestones JSON
[
{
"id":0,
"name":"None"
},
{
"id":1,
"name":"Milestone 1"
},
{
"id":2,
"name":"Milestone 2"
},
{
"id":3,
"name":"Milestone 3"
},
{
"id":4,
"name":"Milestone 4"
}
]
What I need
Milestones Array Of OBjects
var taskMilestonesArray = [{
id: 0,
name: 'None',
},
{
id: 1,
name: 'Milestone 1',
},
{
id: 2,
name: 'Milestone 2',
},
{
id: 3,
name: 'Milestone 3',
},
{
id: 4,
name: 'Milestone 4',
}];
UPDATE
I just realized they are both in almost exact same format already. I just need to pass the array of objects into a library that expects it to be in that format and I don't think I can pass the JSON in.
If you have that JSON in a string (for the sake of the example, I will assume you have a variable named yourJsonString that holds your json), you can parse it:
var taskMilestonesArray = JSON.parse(yourJsonString);
Use JSON.parse api to convert json string to the javascript object.
var taskMilestonesArray = JSON.parse('< milestones json string >');

Categories

Resources