Javascript arrays how to print sorted elements - javascript

I have a question about arrays. I'm new to javascript and I'm writing a program that has a function where it filters 20 elements of an array by category. That is, I have 3 buttons where, by clicking on one of them, the function is turned on and it starts displaying the filtered elements. Please tell me how can this be done? I have already tried a bunch of ways, but in the end nothing happened, although I think that I made a mistake somewhere.
array:
window.products = [
{
id: "i8",
title: "Iphone 8",
description:
"The iPhone 8 ",
price: 19900,
discontinued: false,
categories: ["c1"]
},
{
id: "i10",
title: "Iphone X",
description: "Iphone 10",
price: 39900,
discontinued: false,
categories: ["c1"]
},
{
id: "i11",
title: "Iphone 11",
description: "The iPhone 11 ",
price: 69900,
discontinued: false,
categories: ["c1"]
};
my function
function myFunction() {
document.getElementById("selected-category").innerHTML = "Iphones";
document.getElementById("category-products").innerHTML = "";
for (i = 0; i < 20; i++) {
document.getElementById("category-products").innerHTML = window.id;
const found = window.products.find(window.products.categories == "c1");
console.log(found);
}
}
part html code with button
<button onclick="myFunction()">Iphones</button>

First, you have syntax error in your windows.products = [ ... };. It's not closed properly (you need a ] before the };.
Then, the find method needs to be passed a function that processes an element of the Array. What you tried window.products.categories == "c1" evaluates to false, because the property categories does not exist in the window.products array. You get undefined on the left hand side and a string on the right hand side, so it's always false. You'd get "false is not a function".
Examples of using find() with a function:
const found = window.products.find( element => element.categories == "c1" );
or
const found = window.products.find( function(element) {
return element.categories == "c1"
});
But then:
The above == "c1" isn't what you should use, because it only matches due to type coercion from an array to a string, and only matches when the categories has only "c1" and no other elements. You should use includes method.
"find" will only give you one matching product. Use "filter" to find all matching ones.
If you only need to search for one key "c1", you can use
const found = window.products.filter( product=> product.categories.includes("c1")); and for two keys "c1" and "c2": const found = window.products.filter( product => product.categories.includes("c1") && product.categories.includes("c2"));
But I don't think you should use the above, because you should handle the case where the user searches for multiple keys.
const searchList = ['c1', 'c2', 'c3']
const found = window.products.filter ( function( product) {
//returns true if element.categories contains all of 'c1', 'c2' and 'c3'
return searchList.every( searchKey => product.categories.includes(searchKey)) ;
})
You can also do the search in one line, but may be harder to read :
const searchList = ['c1', 'c2', 'c3']
const found = window.products.filter ( product => searchList.every( searchKey => product.categories.includes(searchKey)) );

Related

Javascript findindex performance issue

I am having an array as like this
var projectItemList=[{
"id":1,
"projectid":"a0I3l00001YiS67EAF",
"date":"2021-06-18",
"task":"",
"starttime":"",
"endtime":"",
"description":"",
"hours":"",
"projectname":"MyCOmp1",
"computedclass":"lookupclass1"
}, {
"id":1,
"projectid":"a0I3l00001YiS67EAF",
"date":"2021-06-18",
"task":"",
"starttime":"",
"endtime":"",
"description":"",
"hours":"",
"projectname":"Myproject",
"computedclass":"lookupclass1"
}];
and this array grows with n number of rows and I am pushing the dynamic constructed rows to the above array by incrementing the id.
and depending on keystroke I am changing the description of objects by finding the index and I am using this method to find the index
findIndex(id) {
return this.projectItemList.findIndex((obj => obj.id == id));
}
this.projectItemList[this.findIndex(id)].description ='xxxxxxx'
If the array length is 5 then things are fine. If the array grows more than 10, say 50 or 100
then its taking some delay to find the index and causing the issue.
I tried with many options but still same issue
return this.projectItemList.map(function(x) {
return (x.id);
}).indexOf(id);
How to overcome this performance issue?
If you can't change the structure of the array, you can run find method for the array.
var projectItemList = [{
"id":1,
"projectid":"a0I3l00001YiS67EAF",
"date":"2021-06-18",
"task":"",
"starttime":"",
"endtime":"",
"description":"",
"hours":"",
"projectname":"MyCOmp1",
"computedclass":"lookupclass1"
}, {
"id":2,
"projectid":"a0I3l00001YiS67EAF",
"date":"2021-06-18",
"task":"",
"starttime":"",
"endtime":"",
"description":"",
"hours":"",
"projectname":"Myproject",
"computedclass":"lookupclass1"
}];
const findIndex = id => projectItemList.find(i => i.id === id);
findIndex(1).description = 'bar';
console.log(projectItemList);
The complexity will be n, where n is the number of items in the array.
But the best solution, in my opinion, is changing your data to something like:
var list = {
1: {
name: 'name for 1',
description: 'description for 1',
},
2: {
name: 'name for 2',
description: 'description for 2',
}
};
from where, you can find the item like
list[1];
in 1 step.

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

Javascript object as a type of mini database?

Is it possible to use a JavaScript object as a type of mini database? I often find myself needing a kind of database structure when I'm coding in JS but it feels like overkill to use an actual database like MySQL (or similar).
As an example, let's say I need to structure this data as a JS object:
Object idea: Stuff to sell
Items to sell: The junk in the garage
Object structure: List all items including item name, item condition, and item value
In order to make this into a JS object I would maybe write:
var stuffToSell = {};
Then my first item would maybe look like:
var stuffToSell = {
item : "Coffee Maker",
condition : "Good",
price : 5
};
Now to me this seems like I'm on the right track, until I come to add another item and I end up having to use the properties item, condition, and price again in the same JS object — which feels wrong? — or is it?? At this point my brain keeps shouting the word "ARRAY!" at me but I just can't see how I can use an array inside the object, or an object inside an array to achieve what I want.
My end goal (in this simplified example) is to be able to then use object-oriented syntax to be able to access certain items and find out specific information about the item such as price, condition etc. For example if I want to know the price of the "coffee maker" I would like to write something like:
stuffToSell["coffee maker"].price
...and then the result above should be 5.
I feel like I'm on the right track but I think I'm missing the array part? Could someone please tell me what I'm missing or maybe what I'm doing completely wrong! And also if it is wrong to have duplicate property names in the same JS object? For example, is it okay to have:
var stuffToSell = {
item : "Coffee Maker",
price : 5,
item : "Mountain Bike",
price : 10,
item : "26 inch TV",
price : 15
};
...it seems wrong because then how does JS know which price goes with which item??
Thanks in advance :)
You're definitely on the right track!
A lot of people will refer to what you're talking about as a hash.
Here's my suggested structure for you:
var store = {
coffee_maker: {
id: 'coffee_maker',
description: "The last coffee maker you'll ever need!",
price: 5,
},
mountain_bike: {
id: 'mountain_bike',
description: 'The fastest mountain bike around!',
price: 10,
},
tv: {
id: 'tv',
description: 'A big 26 inch TV',
price: 15,
},
}
Having a structure like that will let you do this:
store.mountain_bike.price // gives me 10
Need an array instead, say for filtering or looping over?
Object.keys gives you an Array of all the object's keys in the store ['coffee_maker', 'mountain_bike', 'tv']
// Now we just have an array of objects
// [{id: 'coffee_maker', price: 5}, {id: 'mountain_bike', price: 10} ...etc]
var arr = Object.keys(store).map(el => store[el])
Need to just filter for items that are less than 10?
This will give us an array of products less than 10:
// gives us [{id: 'coffee_maker', price: 5}]
var productsUnder10 = arr.filter(el => el.price < 10)
These techniques can be chained:
var productsOver10 = Object.keys(store)
.map(el => store[el])
.filter(el => el.price > 10)
Need to add a product?
store['new_product'] = {
id: 'new_product',
description: 'The Newest Product',
price: 9000,
}
Here's another way, which would be good to start getting used to.
This is a 'safe' way to update the store, read up on immutability in javascript to learn about it
store = Object.assign({}, store, {
'new_product': {
id: 'new_product',
description: 'The Newest Product',
price: 9000,
}
})
...and another way, that you should also read up on and start using:
This is the object spread operator, basically just an easier way to work with immutable structures
store = {
...store,
'new_product': {
id: 'new_product',
description: 'The Newest Product',
price: 9000,
}
}
Resources
JavaScript Arrow Functions
Object and Array Spread Syntax
Immutable Javascript using ES6 and beyond
You can actually use json or create an array of objects.If using a separate file to store the objects, first load the file. Use array filter method to get an new array which matches the filter condition , like you want to get the item with id 1. This will return an array of objects.
var dict = [{
'id': 1,
'name': 'coffee-mug',
'price': 60
},
{
'id': 2,
'name': 'pen',
'price': 2
}
]
function getItemPrice(itemId) {
var getItem = dict.filter(function(item) {
return item.id === itemId
});
return getItem[0].price;
}
console.log(getItemPrice(1))
JSON objects don't support repeated keys, so you need to set unique keys.
Put an id as your key to group your items:
var stuffToSell = {
'1': {
item: "Coffee Maker",
price: 5
},
'2': {
item: "Mountain Bike",
price: 10
}
.
.
.
}
Now you can access the item's price very fast.
Look at this code snippet (Known Ids)
var stuffToSell = {
'1': {
item: "Coffee Maker",
price: 5
},
'2': {
item: "Mountain Bike",
price: 10
},
'3': {
item: "26 inch TV",
price: 15
}
};
let getPrice = (id) => stuffToSell[id].price;
console.log(getPrice('1'));
See? the access to your items it's fast and your code follows a readable structure.
Look at this code snippet (Item's name as key)
var stuffToSell = {
'Coffee Maker': {
price: 5
},
'Mountain Bike': {
price: 10
},
'26 inch TV': {
price: 15
}
};
let getPrice = (id) => stuffToSell[id].price;
console.log(getPrice('Coffee Maker'));
Look at this code snippet (Item's name: price)
var stuffToSell = {
'Coffee Maker': 5,
'Mountain Bike': 10,
'26 inch TV': 15
};
let getPrice = (id) => stuffToSell[id];
console.log(getPrice('Coffee Maker'));

JavaScript : searching an array and returning value after user input

var data = [{
id: 'A1',
name: 'Minstrels'
}, {
id: 'A2',
name: 'Bounty'
}, {
id: 3,
name: 'Crunchie'
}, {
id: 4,
name: 'bar'
}];
var rl = require('readline')
var prompts = rl.createInterface(process.stdin, process.stdout);
prompts.question('Which Product do you want to purchase? ',
function(Answer1) {
//missing code goes here in order to return Minstrels if the user
//types 'A1' etc..
}
)
I need help in my code. I have enabled user input and made an array, however, I can't think of what my code is missing.
This uses the find() array method to locate the first element matching the given predicate, then additionally handles the case where the item was not located. Because your example uses both strings and numbers for id values, we explicitly coerce each object's id to a string during comparison to simplify the strict comparison:
var item = data.find(i => ("" + i.id) === Answer1);
console.log(item ? item.name : 'No such food');

finding a value in an object

I have an object:
{
id: 16,
defs: {
name: "Depot (Float)", field: "Depot"
}
}
And an array (which can have more than one object in it but for the purposes of this only has one):
[
{
Percentage Monthly Potential: 1,
Area Manager: "Ashar",
Business Unit: "Retail",
Cust no: 68345,
Depot Name: "Leicester",
Group Number: "",
Depot: 14,
Target: 46100
}
]
What I need to do is take the field value from the object and use it to find the key that it matches in the second object and retrieve the value of it, so in this case I should be getting 14.
Any help with this would be much appreciated.
Thanks for your time.
If you are using ES6, you can try this:
const field = lookupObject.defs.field;
const matches = array.map(arrayItem => {
return {
field,
value: arrayItem[field]
}
});
The matches array will contain the data you are interested in.

Categories

Resources