if statement in a mapping - javascript

Currently I'm getting a
continue must be inside a loop
which I recognize as a syntax error on my part because it should be fixed.
Will fixing this to retain this logic in an if statement work with the mapping?
sales = data.map(function(d) {
if (isNaN(+d.BookingID) == false && isNaN(+d["Total Paid"]) == false) {
return [+d.BookingID, +d["Total Paid"]];
} else {
continue;
}
});

map is meant to be 1:1.
If you also want filtering, you should filter and then map
sales = (
data
.filter(d => (!isNaN(+d.BookingID)&& !isNaN(+d["Total Paid"]))
.map(d => [+d.BookingID, +d["Total Paid"]];
});

As others have mentioned, you cannot "continue" from within a map callback to skip elements. You need to use filter. To avoid referencing the fields twice, once in the filter, and once in the map, I'd filter afterwards:
sales = data
.map(d => [+d["bookingId"], +d["Total Paid"]])
.filter(([id, total]) => !isNaN(id) && !isNaN(total));
or, to make it easier in case you later want to include additional values in the array:
sales = data
.map(d => [+d["bookingId"], +d["Total Paid"]])
.filter(results => results.every(not(isNaN)));
where
function not(fn) { return x => !fn(x); }
or
function allNotNaN(a) { return a.every(not(isNaN)); }
and the, using parameter destructuring:
sales = data
.map(({bookingId, "Total Paid": total)) => [bookingId, total])
.filter(allNotNaN);

Related

ngx dropdown list get selected values

I am trying to use ngx dropdown list like this:
<ngx-dropdown-list [items]="categoryItems" id="categoriesofdata" [multiSelection]="true"
[placeHolder]="'Select categories'"></ngx-dropdown-list>
And I am getting all selected values like:
get selectedCategories() {
const items = this.categoryItems.filter((item: any) => item.selected);
return items.length ? JSON.stringify(items.map(item => ({
value: item.value
}))) : '';
}
and output looks like:
[{"value":"Surname"},{"value":"Address"}]
I want to get only for example Surname instead of value and Surname.
[0].value
How Can I do this?
Should I use for loop or is better option?
I think you're almost there, in fact you're doing a little too much. Your map function should just return the value you are interested in rather than creating a new structure.
get selectedCategories() {
const items = this.categoryItems.filter((item: any) => item.selected);
return items.length ? JSON.stringify(items.map(item => item.value)) : '';
}
Edit:
And as a personal preference, I would refactor to something like this:
get selectedCategories() {
if (!this.categoryItems.length) {
return '';
}
const surnames = this.categoryItems
.filter(item => item.selected)
.map(item => item.value);
return JSON.stringify(surnames);
}
I prefer to get out of a function early in the case where no further processing is required. And I would return the result of chained filter and map functions into a new surnames variable. The named variable signals the intention of the code, and keeps the array logic together.
This is just my preference though. Your code was almost there functionally.

Filter table data

I want to filter a table based on few conditions .. Below is the sample image
code I've tried
this.reportData.filter(it => {
if (
it.startTimeFilter.includes(this.startdatefilter) &&
it.endTimeFilter.includes(this.enddatefilter) &&
it.status.toLowerCase().includes(this.status)
) {
this.filteredData.push(it);
}
});
Ok, I can give you some hint to achieve this as I do not have full code. Make sure this.reportData is never changed as we need all data to have filtering
applyFiltering(){
this.dataToShowOnUI = getFilteredData();
}
getFilteredData(): any[]{
let filteredData = JSON.parse(JSON.stringify(this.reportData));
if(this.startdatefilter && this.enddatefilter){
filteredData = filteredData.filter(it =>
it.startTimeFilter.includes(this.startdatefilter) &&
it.endTimeFilter.includes(this.enddatefilter)
);
}
if(this.status){
filteredData = filteredData.filter(data => data.status.toLowerCase().includes(this.status))
}
if(this.operatingSystem){
filteredData = filteredData.filter(data => data.operatingSystem.toLowerCase().includes(this.operatingSystem))
}
// and so on ...
return filteredData;
}
I'm assuming that this.reportData and this.filteredData are arrays. Then the correct way of using filter method is the following:
this.filteredData = this.reportData.filter(it =>
it.startTimeFilter.includes(this.startdatefilter) &&
it.endTimeFilter.includes(this.enddatefilter) &&
it.status.toLowerCase().includes(this.status)
);
Basically, the parameter of filter should be a function that returns boolean value (which tells if the element should be kept as result), and it returns the filtered new array without modifying the given one.

Trouble with React/JS filter

I am trying to implement a filter function that is able to search in two separate JSON fields when a user types in a search bar. Searching the whole JSON returns errors and if I repeat this function, the two similar functions cancel each other out.
My current filter function:
let filteredOArt = origArt.filter((origAItem) => {
return origAItem.authors.toLowerCase().includes(this.state.search.toLowerCase())
});
I want to be able to have the search look within the "authors" field as well as a "description" field.
Before the React render, I have this function listening to the state:
updateSearch(event) {
this.setState({ search: event.target.value })
}
Then my search function is in an input field in the React return:
<h6>Search by author name: <input type="text" value={this.state.search} onChange={this.updateSearch.bind(this)} /></h6>
You can tweak the function a bit like this
let filteredOArt = origArt.filter((origAItem) => {
return (
(origAItem.authors.toLowerCase().includes(this.state.search.toLowerCase())||
(origAItem.description.toLowerCase().includes(this.state.search.toLowerCase())
)
)
});
You actually can do a filter for both fields.
Given you have your searchValue and your array with the objects you could filter this way:
const filterByAuthorOrDescription = (searchValue, array) =>
array.filter(
item =>
item.authors.toLowerCase().includes(searchValue.toLowerCase()) ||
item.description.toLowerCase().includes(searchValue.toLowerCase())
);
const filtered = filterByAuthorOrDescription(this.state.search, articles);
filtered will now contain an array of objects that contain your searchValue in either description or authors that you can map through.
You could use some to check if the filter is positive for at least one field :
let filteredOArt = origArt.filter(origAItem => ['authors', 'description'].some(field => origAItem.[field].toLowerCase().includes(this.state.search.toLowerCase())))
Just iterate over the different field names you want to use.
Some will return true if any of the fields mentioned contains your string and avoid repetitions in your code.
Long syntax :
origArt.filter(origAItem => {
return ['authors', 'description'].some(field => origAItem.[field].toLowerCase().includes(this.state.search.toLowerCase()))
})

Steam API, different json format

Recently i integrated CSGO stats in my discord bot, but today i saw that for almost every player the API sends a different json data.
Here 2 examples:
https://jsonblob.com/58688d30-26d0-11e8-b426-7b3214778399
https://jsonblob.com/52ed0c3f-26d0-11e8-b426-43058df4a5a6
My question was how to request the data properly so a win is really a win and not a kill.
.addField('**Wins:**', `${object.playerstats.stats[5].value}`, true)
.addField('**Time played:**', `${object.playerstats.stats[2].value}` + ' minutes', true)
.addField('**Kills:**', `${object.playerstats.stats[0].value}`, true)
.addField('**Deaths:**', `${object.playerstats.stats[1].value}`, true)
.addField('**Bombs planted:**',`${object.playerstats.stats[3].value}`, true)
.addField('**Money earned:**',`${object.playerstats.stats[7].value}`, true)
.addField('**Knife kills:**',`${object.playerstats.stats[9].value}`, true)
.addField('**Headshot kills:**',`${object.playerstats.stats[24].value}`, true)
.addField('**Dominations:**',`${object.playerstats.stats[39].value}`, true)
.addField('**Rounds played:**',`${object.playerstats.stats[44].value}`, true)
The name property of stats items appear to be unique enough to find. You can use array.find to look for the correct stat by name.
const stats = object.playerstats.stats
const totalKills = stats.find(s => s.name === 'total_kills').value
const totalDeaths = stats.find(s => s.name === 'total_deaths').value
Taking it further, you can use array.reduce to generate an object whose key is name and value is value for each item in the array. This way, you access it like an object.
const stats = object.playerstats.stats
const statsObj = stats.reduce((c, e) => (c[e.name] = e.value, c), {})
const totalKills = statsObj.total_kills
const totalDeaths = statsObj.total_deaths
Rather than trying to reference the array indexes, why not convert the API response into an easier-to-parse format?
// do this once...
let playerStats = {};
object.playerstats.stats.forEach(s => playerStats[s.name] = s.value);
// ...then you can use the playerStats variable however you need:
.addField('**Kills:**', `${playerStats.total_kills}`, true)
.addField('**Wins:**', `${playerStats.total_wins}`, true)
The stats array is just not sorted. you can use .find() to get the correct entry from the stats.
for example
const totalWins = object.playerstats.stats.find(stat => {
return stat.name === 'total_wins';
});
.addField('**Wins:**', `${totalWins.value}`, true)
You are approching this problem the wrong way.
JSON is not a format that is ordered. What that means is that there is no guarantee that the JSON data will return in the same order everytime. It is not a default of the API.
There is one way you could still use your way: by sorting the 'stats' array by name. but it is a long operation and not a very good idea.
The way do to this is to do a lookup by name.
For example, if you want to find the wins, you do this :
object.playerstats.stats.find(elem => elem.name === 'total_wins').value;
The find function does a lookup and returns the first element matching the predicate (elem.name === 'total_wins'). It returns null if not element matched the predicate (so be careful here).
You could do a function that returns a value for you :
findValue(statsArray, name) {
const entry = statsArray.find(elem => elem.name === name);
return entry ? entry.value : '?';
}
And then your code would look like this :
...
.addField('**Wins:**', findValue(object.playerstats.stats, 'total_wins'), true)
...
The main thing here is : never assume fields in a JSON will return the same every time. Always use lookup, and not indexes (unless it is sorted).

D3: Nest and excluding certain keys

I am new to d3 and trying to plot some data in one box for each of four specific states, similar to this page but with states not continents, and a lot more data points. I have a json dataset of more than 42,000 entries supposedly from just those 4 states.
To key by state, I used this:
d3.json("data/business.json",function(json) {
var data=d3.nest()
.key(function(d) {return d.state;})
.sortKeys(d3.ascending)
.entries(json);
Then later make one box for each state:
// One cell for each state
var g=svg.selectAll("g").data(data).enter()
.append("g")
(attributes, etc)
Fine, but I soon found that the dataset includes some data from several states I don't want to consider so it was plotting more boxes than I wanted.
I would like a way to exclude the data that isn't from the four states without altering the original data file. What is the best way to go about this?
Filter your json:
var keep = ["state1", "state2", "state3", "state4"];
json = json.filter(function(d) { return keep.indexOf(d.state) > -1; });
It's possible to filter the output from d3.nest rather than the original array:
function trim(nested, f) {
return nested
.filter(function (e) {
return f(e.key)
})
.map(function (e) {
if (e && (typeof e =='object') && Array.isArray(e.values) && ('key' in e)) {
return { key: e.key, values: trim(e.values, f)}
}
else return e
})
}
For instance:
function isNewEngland(st) {
return ["ME","VT","NH","MA", "CT", "RI"].indexOf(st)>=0
}
data = trim(data, isNewEngland)

Categories

Resources