Javascript forEach where value equals value in different array - javascript

Javascript:
$(document).ready(function() {
const ores = "../js/json/oreList.json";
const priceURL = "https://esi.tech.ccp.is/latest/markets/prices/?datasource=tranquility";
let oreArray = [];
let priceArray = [];
let total = 0;
// Retrieve list of ores
function getOres() {
$.getJSON(ores, function(ores) {
ores.forEach(function(ore) {
total++;
if (total === 48) {
getPrices();
}
oreArray.push(ore);
});
});
}
// Retrieve all items & prices via API
function getPrices() {
$.getJSON(priceURL, function(prices) {
prices.forEach(function(data) {
priceArray.push(data);
console.log(data);
});
});
}
getOres();
});
The first function creates an internal array from my .JSON file and the second function creates an internal array from the URL.
In the first array oreArray, an object looks like this:
{ id: 1234, name: "Title" }
In the second array priceArray, an object looks like this:
{ type_id: 1234, average_price: 56.34 }
My oreArray has 48 objects and unfortunately the priceArray has about 11,000 objects. I need to create a new array by comparing the two arrays and building new objects, where the ID's match. So for example objects in newArray would look like:
{ id: 1234, name: "Title", average_price: 56.34 }
Basically I'm having trouble figuring out the logic for:
For each object in oreArray, find the object with the same ID value in priceArray and append the new array with a new object using values from both arrays.

I would do it this way:
const ores = "../js/json/oreList.json",
priceURL = "https://esi.tech.ccp.is/latest/markets/prices/?datasource=tranquility";
let oreArray,
priceArray,
joinedArray = [];
function getOres() {
$.getJSON(ores, function(ores) {
oreArray = ores;
getPrices();
});
}
function getPrices() {
$.getJSON(priceURL, function(prices) {
priceArray = prices;
joinPrices();
});
}
function joinPrices() {
oreArray.forEach(function(ore) {
var matchingPrice = getMatchingPrice(ore);
if(matchingPrice !== false) {
joinedArray.push({
id: ore.id,
name: ore.name,
average_price: matchingPrice.average_price
});
}
});
}
function getMatchingPrice(ore) {
for(var i=0; i<priceArray.length; i++) {
if(priceArray[i].type_id === ore.id) {
return priceArray[i];
}
}
return false;
}
getOres();

I think that a good way to approach this problem is by changing the data structure of the average prices a little bit.
Instead of having them in an array, where each item has type_id and average_price field, you might want to consider using an object to store them, where the key is the type_id and the value is the average_price.
To be more concrete, you can replace:
prices.forEach(function(data) {
priceArray.push(data);
});
With:
const pricesMap = {};
prices.forEach(price => {
pricesMap[price.type_id] = price.average_price
});
And when looping on the oreArray, you can access each product's average_price by simply referring to pricesMap[ore.id]
You can check out this JSBin: http://jsbin.com/fogayaqexe/edit?js,console

You can use reduce to loop over each oreArr item and collect the data you need in the accumulator:
var oreArr=[
{ id: 1234, name: "Title" },
{ id: 2234, name: "2Title" },
]
var priceArr= [
{ type_id: 1234, average_price: 56.34 },
{ type_id: 2234, average_price: 256.34 },
{ type_id: 3234, average_price: 56.34 },
{ type_id: 4234, average_price: 56.34 },
]
var resArr = oreArr.reduce((ac,x) => {
var priceMatch = priceArr.find( z => z.type_id === x.id )
if(! priceMatch)
return ac //bail out if no priceMatch found
var res = Object.assign({}, x, priceMatch)
ac.push(res)
return ac
},[])
console.log(resArr)
other methods used:
arrayFind to check intersection
Object.assign to create the merged object to populate the accumulator

I suggest you to change your small json as object
eg : '{"1234":{"id": 1234, "name": "Title" }}';
var json = '{"1234":{"id": 1234, "name": "Title" }}';
oreArray = JSON.parse(json);
alert(oreArray['1234'].name); // oreArray[priceArraySingle.id].name
we can easily match priceArray id with oreArray.

Related

Find a property (which is stored as a string in a variable) in an array of objects

I have an array of objects which store the data of different 'pupils'.
var pupils = [
{
id: 0,
name: 'will'
},
{
id: 1,
name: 'megan'
}
];
I want to create a function called 'findPupil' which takes three parameters: the property you know, the value you know it to be and the property you want to find.
Say you know that the pupil you are looking for has an id of 1 but you don't know their name. In this case, you would call the function like this:
var name = findPupil('id', 1, 'name'); // should now store 'Megan' as a string
Here is the function I have written:
function findPupil(property, value, find) {
pupils.forEach(function(pupil) {
if(pupils[pupil][`${property}`] === value) {
return pupils[pupil][`${find}`];
}
});
}
Calling this function returns the following:
Error: Cannot read property 'id' of undefined
How do I make this function work?
Use Array.find() to find an object with the property you know, or a default if an object is not found. Extract the find property from the object:
const pupils = [{"id":0,"name":"will"},{"id":1,"name":"megan"}];
const findPupil = (property, value, find) =>
(pupils.find(o => o[property] === value) || {})[find];
const name = findPupil('id', 1, 'name');
console.log(name);
You could use .find() for that.
var pupils = [{id: 0, name: 'will'},{id: 1,name: 'megan'}];
function getByPropertyAndValue(knownProp, knownValue, desiredProperty) {
let pupil = pupils.find(p => p[knownProp] === knownValue); //Find pupil by property and value
return pupil && pupil[desiredProperty]; //Return the value, or undefined if not found
}
console.log(getByPropertyAndValue("id", 1, "name"));
Most of your code is correct except for the part of your if statement. Please find working example -
var pupils = [{
id: 0,
name: 'will'
},
{
id: 1,
name: 'megan'
}
];
function findPupil(property, value, find) {
let result
pupils.forEach(function(pupil) {
if (pupil[property] === value) {
result = pupil[find];
}
});
return result
}
var name = findPupil('id', 1, 'name');
console.log(name)
var pupils = [
{ id: 0, name: 'will' },
{ id: 1, name: 'megan' }
];
function findPupil(property, value, find) {
var find_value = '';
for (var i = 0; i < pupils.length; i++) {
if (find_value == '') {
Object.keys(pupils[i]).forEach(function (key) {
if (key == property && pupils[i][key] == value) {
find_value = pupils[i][find];
}
});
} else {
break;
}
}
console.log(find_value);
return find_value;
}
var name = findPupil('id', 1, 'name');

Filter Array that contains specific symbol or words in Javascript

Hello I would like to ask for help on filtering my Array currently I have a list of array that contains words but I want to filter out those with symbol ("#") to be remove on the array
function InitializeV3() {
var req = SymbolList; //obj with symbol property
for (var i = 0; i < req.lenght; i++) {
if (req[i].smybol.includes("#")) {
req.splice(req[i], 1);
}
}
console.log(req);
};
For a simple array you can do it like this with the filter method:
var req = ['test','#test1','#test2','test3','test4'];
var result = req.filter(item => !item.includes("#"));
console.log(result);
And if you have an array of objects:
var req = [{symbol: 'test'},{symbol: '#test1'},{symbol: '#test2'},{symbol: 'test3'},{symbol: 'test4'}]
var result = req.filter(item => !item.symbol.includes('#'));
console.log(result);
function InitializeV3() {
// For simple array
var req = ['test',
'#test1',
'#test2',
'test3',
'test4'
]
var filtered = req.filter(item => !item.includes('#'))
console.log(filtered)
};
InitializeV3();
// For array of objects
var req = [{
symbol: 'test'
}, {
symbol: '#test1'
}, {
symbol: '#test2'
}, {
symbol: 'test3'
}, {
symbol: 'test4'
}]
// Use the following
var filtered = req.filter(item => !item.symbol.includes('#'))
console.log(filtered)
First of all - req array should contain objects (current syntax is incorrect):
var req = [
{ symbol: 'test' },
{ symbol: '#test1' },
// ...
];
Then you can try with:
const filteredReq = req.filter(item => item.symbol.indexOf('#') === -1);
You can loop over all the keys. But if you have symbol multiple times as key only the last data will be saved.
let SymbolList = {
symbol0:'test',
symbol1:'#test1',
symbol2: '#test2',
symbol3:'test3',
symbol4: 'test4'
};
function InitializeQuotesV3(req) {
for (key in req) {
req[key] = req[key].replace(/#/g,"");
}
return req;
};
console.log(InitializeQuotesV3(SymbolList));
Better you can use JS Regex Regex
var req = [{symbol:'test'} ,
{symbol:'#test1'},
{symbol: '#test2'},
{symbol:'test3'} ,
{symbol: 'test4'}];
let hasHash = /#/;
for (var i = req.length - 1; i >= 0; i--) {
if (hasHash.test(req[i].symbol)) {
req.splice(i,1);
}
}
console.log(req);

Javascript using filter/includes on an array of objects

What is the best way to filter out data that exists within an object?
I was able to do use the below code when data was just an array of values but now I need to filter out any data where the item.QID exists in my array of objects.
Data Obj:
var data = [{
QID: 'ABC123',
Name: 'Joe'
},
{
QID: 'DEF456',
Name: 'Bob
}]
Snippet:
// I don't want to include data if this QID is in my object
this.employees = emp.filter(item =>!this.data.includes(item.QID));
From what I understand, includes only works on an array so I need to treat all of the QID values in my object as an array.
Desired Outcome: (assuming item.QID = ABC123)
this.employees = emp.filter(item =>!this.data.includes('ABC123'));
Result:
var data = [{
QID: 'DEF456',
Name: 'Bob'
}]
UPDATE:
Apologies, I left some things a little unclear trying to only include the necessary stuff.
// People Search
this.peopleSearchSub = this.typeahead
.distinctUntilChanged()
.debounceTime(200)
.switchMap(term => this._mapsService.loadEmployees(term))
.subscribe(emp => {
// Exclude all of the current owners
this.employees = emp.filter((item) => item.QID !== this.data.QID);
}, (err) => {
this.employees = [];
});
The above code is what I am working with. data is an object of users I want to exclude from my type-ahead results by filtering them out.
The question is a little ambiguous, but my understanding (correct me if I'm wrong), is that you want to remove all items from a list emp that have the same QID as any item in another list data?
If that's the case, try:
this.employees = emp.filter(item => !this.data.some(d => d.QID === item.QID))
some is an array method that returns true if it's callback is true for any of the arrays elements. So in this case, some(d => d.QID === item.QID) would be true if ANY of the elements of the list data have the same QID as item.
Try Object#hasOwnProperty()
this.employees = emp.filter(item =>item.hasOwnProperty('QID'));
You can use a for ... in to loop through and filter out what you want:
const data = [{
QID: 'ABC123',
Name: 'Joe'
},
{
QID: 'DEF456',
Name: 'Bob'
}]
let newData = [];
let filterValue = 'ABC123';
for (let value in data) {
if (data[value].QID !== filterValue) {
newData.push(data[value]);
}
}
newData will be your new filtered array in this case
You can use an es6 .filter for that. I also added a couple of elements showing the filtered list and an input to allow changing of the filtered value. This list will update on the click of the button.
const data = [{
QID: 'ABC123',
Name: 'Joe'
},
{
QID: 'DEF456',
Name: 'Bob'
}]
displayData(data);
function displayData(arr) {
let str = '';
document.getElementById('filterList').innerHTML = '';
arr.forEach((i) => { str += "<li>" + i.QID + ": " + i.Name + "</li>"})
document.getElementById('filterList').innerHTML = str;
}
function filterData() {
let filterValue = document.getElementById('filterInput').value;
filterText (filterValue);
}
function filterText (filterValue) {
let newArr = data.filter((n) => n.QID !== filterValue);
displayData(newArr)
}
<input id="filterInput" type="text" value="ABC123" />
<button type ="button" onclick="filterData()">Filter</button>
<hr/>
<ul id="filterList"><ul>

how to grep this Javascript object array?

I have the following object structure:
var mapData =
{
Summary:
{
ReportName: 'Month End Report'
},
NortheastRegion:
{
Property1: 123,
RegionName: 'Northeast'
},
SoutheastRegion:
{
Property1: 456,
RegionName: 'Southeast'
},
}
I want to write a grep function that returns an array of region names. The following function is not returning any values:
var regions = $.grep(mapData, function(n,i)
{
return n.RegionName;
});
What am I missing here?
$.grep is for filtering arrays. Your structure isn't an array. $.grep is also just for filtering, but you're talking about both filtering (leaving out Summary) and mapping (getting just the region names).
Instead, you can use
Object.keys and push:
var regions = [];
Object.keys(mapData).forEach(function(key) {
var entry = mapData[key];
if (entry && entry.RegionName) {
regions.push(entry.RegionName);
}
});
Object.keys, filter, and map:
var regions = Object.keys(mapData)
.filter(function(key) {
return !!mapData[key].RegionName;
})
.map(function(key) {
return mapData[key].RegionName;
});
A for-in loop and push:
var regions = [];
for (var key in mapData) {
if (mapData.hasOwnProperty(key)) {
var entry = mapData[key];
if (entry && entry.RegionName) {
regions.push(entry.RegionName);
}
}
}
...probably others.
That's an object, not an array. According to the jQuery docs, your above example would work if mapData were an array.
You can use lodash's mapValues for this type of thing:
var regions = _.mapValues(mapData, function(o) {
return o.RegionName;
});
ES6:
const regions = _.mapValues(mapData, o => o.RegionName)
As stated in jQuery.grep() docs, you should pass an array as data to be searched, but mapData is an object. However, you can loop through the object keys with Object.keys(), but AFAIK you'll have to use function specific for your case, like:
var mapData =
{
Summary:
{
ReportName: 'Month End Report'
},
NortheastRegion:
{
Property1: 123,
RegionName: 'Northeast'
},
SoutheastRegion:
{
Property1: 456,
RegionName: 'Southeast'
},
};
var keys = Object.keys(mapData),
result = [];
console.log(keys);
keys.forEach(function(key) {
var region = mapData[key].RegionName;
if (region && result.indexOf(region) == -1) {
result.push(region);
}
});
console.log(result);
// Short version - based on #KooiInc answer
console.log(
Object.keys(mapData).map(m => mapData[m].RegionName).filter(m => m)
);
$.grep is used for arrays. mapData is an object. You could try using map/filter for the keys of mapData, something like:
var mapData =
{
Summary:
{
ReportName: 'Month End Report'
},
NortheastRegion:
{
Property1: 123,
RegionName: 'Northeast'
},
SoutheastRegion:
{
Property1: 456,
RegionName: 'Southeast'
},
};
var regionNames = Object.keys(mapData)
.map( function (key) { return mapData[key].RegionName; } )
.filter( function (name) { return name; } );
console.dir(regionNames);
// es2105
var regionNames2 = Object.keys(mapData)
.map( key => mapData[key].RegionName )
.filter( name => name );
console.dir(regionNames2);
Just turn $.grep to $.map and you would good to go.
var regions = $.map(mapData, function(n,i)
{
return n.RegionName;
});

What is the best way to convert an array of strings into an array of objects?

Let's say I have an array of emails:
['a#gmail.com', 'b#gmail.com', 'c#gmail.com']
I need to convert it into an array of objects that looks like this:
[
{
id: 'a#gmail.com',
invite_type: 'EMAIL'
},
{
id: 'b#gmail.com',
invite_type: 'EMAIL'
},
{
id: 'c#gmail.com',
invite_type: 'EMAIL'
}
]
In order to do that, I have written the following code:
$scope.invites = [];
$.each($scope.members, function (index, value) {
let inviteMember = {
'id': value,
invite_type: 'EMAIL'
}
$scope.invites.push(inviteMember);
});
Is there any better way of doing this?
Since you're already using jQuery, you can use jQuery.map() like this:
var originalArray = ['a#gmail.com', 'b#gmail.com', 'c#gmail.com']
var newArray = jQuery.map(originalArray, function(email) {
return {
id: email,
invite_type:'EMAIL'
};
});
jQuery.map() translates all items in a given array into a new array of items. The function I am passing to jQuery.map() is called for every element of the original array and returns a new element that is written to the final array.
There is also the native Array.prototype.map() which is not supported in IE8. If you're not targeting IE8 or if you use a polyfill, then you can use the native .map():
var newArray = originalArray.map(function(email) {
return {
id: email,
invite_type:'EMAIL'
};
});
This pattern
targetArray = []
sourceArray.forEach(function(item) {
let x = do something with item
targetArray.push(x)
})
can be expressed more concisely with map:
targetArray = sourceArray.map(function(item) {
let x = do something with item
return x
})
in your case:
$scope.invites = $scope.members.map(function(value) {
return {
id: value,
invite_type: 'EMAIL'
}
});

Categories