I am trying to build a pie chart in react js which uses highcharts (https://api.highcharts.com/highcharts/) is accepting only the following format for pie chart data (or maybe I'm wrong): Sample Fiddle here: https://jsfiddle.net/react_user1/e9cbsrdL/1/
data: [
{name: 'abc', y: 10},
{name: 'def', y: 90}
]
The data I get from my API looks something like this:
const counts:[
{
"id": "all",
"type": "all",
"count": 1403
},
{
"id": "bad",
"type": "bad",
"count": 0
},
{
"id": "failed",
"category": false,
"type": "failed",
"count": 58
},
{
"id": "changed",
"category": true,
"type": "changed",
"count": 123
}
So I am trying to achieve three things here:
1. Remove the first {}, with the "id": "all"
2. Rename the key: "id" to name & "count" to y
3. Remove the keys: "type" & "category" & their data
Thanks for any help you could provide, even a partial answer that can help would be appreciated.
I think you can use Array.prototype.filter() and Array.prototype.map() combination.
With filter() you can remove the value what you don't need - in your case all - then with map() you can create a new structure for you array.
From the documentations - link mentioned above:
The filter() method creates a new array with all elements that pass the test implemented by the provided function.
The map() method creates a new array populated with the results of calling a provided function on every element in the calling array.
Just like this:
const counts = [
{
"id": "all",
"type": "all",
"count": 1403
},
{
"id": "bad",
"type": "bad",
"count": 0
},
{
"id": "failed",
"category": false,
"type": "failed",
"count": 58
},
{
"id": "changed",
"category": true,
"type": "changed",
"count": 123
}
];
const result = counts.filter(f => f.id !== 'all')
.map(e => ({ name: e.id, y: e.count }));
console.log(result);
I hope this helps!
You can also provide data as an array of arrays:
series: [{
data: (() => counts.map(
item => [item.id, item.count]
))()
}]
Live demo: https://jsfiddle.net/BlackLabel/op4s13dm/
try this
renderarrayobjects = () => {
return this.state.arrayname.map((Arrayelement, Indexvalue) => {
return (
<View style={styles.btnColor}>
<Text style={styles.tagtext}>{Arrayelement}</Text>
<TouchableOpacity
Indexvalue={Indexvalue}
onPress={() => {
this.remove(Arrayelement);
}}>
<Image style={styles.editskill} source={deletarray} />
</TouchableOpacity>
</View>
);
}); };
The index value is the Index value.
this will render a list of Array items and we add an image that will be pressed to delete array the cross image will appear after every element of an array
removePeople(Arrayelement) {
var array = [...this.state.Arrayelement];
var index = array.indexOf(Arrayelement);
if (index !== -1) {
array.splice(index, 1);
this.setState({Arrayelement: array});
} }
this method will delete array objects.
Hope it helps .feel free for doubts
Related
I am building a Blog app and I am trying to get results but it is showing duplicate results, I am trying to remove the duplicate results from the array.
But the problem is there are two key and values in each dict inside array, One is unique and other can be same so I am trying to distinct based on same array, It worked But the other key and value pair (which is unique) is not attaching with the other pair.
response which is returning from db
[
{
"id": 2,
"name": "user_1"
},
{
"id": 3,
"name": "user_3"
},
{
"id": 4,
"name": "user_3"
}
]
App.js
function App() {
const [blogs, setBlogs] = useState([]);
axios.get("retract_blogs/").then((res) => {
// Here I also want to attach "id"
setBlogs({[...new Set(res.data.data.map(x => x.name))]})
}
return(
<div>
{
blogs.map((user) =>
<div>
{user.name}
// Here I wamt to show ID
// {user.id}
</div>
}
</div>
)
}
I want to add id with x.username, I also tried using
setBlogs({data:[...new Set(res.data.data.map(x => x.name, x.id))]})
But it showed
x is not defined
But I am trying to add both name and id, and remove duplicates based on name not id.
I have tried many times but it is still not working.
To keep the id of the last occurence you can create a Map of the array keyed by name and then convert back to an array using the iterator returned by Map.values(). This works by overwriting earlier entries in the Map with the same name.
const users = [{ "id": 2, "name": "user_1" }, { "id": 3, "name": "user_3" }, { "id": 4, "name": "user_3" }];
const result = [...new Map(users.map((user) => [user.name, user])).values()];
console.log(result);
// [ { id: 2, name: 'user_1' }, { id: 4, name: 'user_3' } ]
If you instead want to keep the id of the first occurence of a name you can use a slightly modified 'group by' grouping into an object by name (here in a reduce() call, but it could easily be done in a standard loop as well) before taking the Object.values. This works by only setting the accumulator[name] property if it doesn't already exist, here using logical nullish assignment (??=)
const users = [{ "id": 2, "name": "user_1" }, { "id": 3, "name": "user_3" }, { "id": 4, "name": "user_3" }];
const result = Object.values(users.reduce((a, c) => (a[c.name] ??= c, a), {}));
console.log(result);
// [ { id: 2, name: 'user_1' }, { id: 3, name: 'user_3' } ]
Im trying to take JSON data and pass it into my 'HistoryChart' Component to try and map the dates and prices into two arrays so that I can present them on my chart. However, I keep getting undefined errors.
Here is the JSON Data:
{
"_id": 1,
"name": "",
"brand": "",
"image": "",
"sources": [],
"history": [
{
"_id": 3,
"price": "299.99",
"product": 1,
"date": "2021-07-01"
},
{
"_id": 4,
"price": "399.99",
"product": 1,
"date": "2021-07-08"
},
{
"_id": 5,
"price": "499.99",
"product": 1,
"date": "2021-07-15"
},
{
"_id": 6,
"price": "599.99",
"product": 1,
"date": "2021-07-22"
},
{
"_id": 7,
"price": "699.99",
"product": 1,
"date": "2021-07-29"
}
]
}
Here is my HistoryChart Component:
function HistoryChart({product}) {
var dates = product.history.map(function(e){ //<-- The Problem lies here where it says cannot map undefined.
return e.date;
});
var prices = product.history.map(function(e){
return e.price;
});
return (
<div>
<Line
data={{
labels: dates,
datasets: [{
label: `Average Price History (ID: ${product._id})`, //<-- This part works
backgroundColor:/* 'transparent' */ '#00ad0e',
borderColor: '#00ad0e',
data: prices,
}]
}}
width={100}
height={50}
options={{ maintainAspectRatio: true }}
/>
</div>
)
}
I am also using redux to get the Data:
const productDetails = useSelector(state => state.productDetails)
const {error, loading, product} = productDetails
And the data is passed into the HistoryChart Component like this:
<HistoryChart product={product}/>
Any Help would be Much appreciated, Thanks.
Sorry if this is not your principal problem, but same time when .map resulting in undefined the most simple adjust is verify if your array is undefined.
So in my projects i always check first if array is undefined, i will use your code to do a example
function HistoryChart({product}) {
if (product !== undefined){
var dates = product.history.map(function(e){
return e.date;
});
var prices = product.history.map(function(e){
return e.price;
});
}
Try this aproach and let me know if this work.
Cause of Error
As the data come from server, it take some time to load. and you get the undefine error because 1st time you want to access history of object product which is not yet loaded successfully.
Solution
const price = product && product.history.map(//do what you want)
use key values of object this way not cause any error because if product is not loaded it does'nt call map function and when product object loaded successfully it will call map function
I am hitting an endpoint that is returning an array of objects, each object can potentially have a set of fields, e.g.,
const FIELDS = [
'id',
'title',
'contributor',
'mediatype',
'source'
]
However, some objects will only have some of those fields, some may have all.
const items = [
{
"id": 1,
"title": "some title 1",
"contributor": "bob",
"mediatype": "text"
},
{
"id": 2,
"title": "some title 2",
"mediatype": "text"
}.
{
"id": 3,
"title": "some title 3",
"mediatype": "movies"
"source": "comcast"
}
]
I want to "normalize" all the objects such that every single one contains every expected field, filling the "gaps" with null, or some falsey value such that graphql (which I intend to eventually feed it into) is happy.
const items = [
{
"id": 1,
"title": "some title 1",
"contributor": "bob",
"mediatype": "text",
"source": null
},
{
"id": 2,
"title": "some title 2",
"mediatype": "text",
"contributor": null,
"source": null
}.
{
"id": 3,
"title": "some title 3",
"mediatype": "movies",
"contributor": null,
"source": "comcast"
}
]
My "nasty" looking code looks something like this
const normalize = items =>
items.map(item => {
FIELDS.forEach(f => {
if (!item[f]) {
item[f] = null;
}
});
return item;
});
Any suggestions for writing this more elegantly - either with vanilla JS or lodash, which I am equally open to using as its already available in my codebase?
You can use spread syntax, but then it would be better to define FIELDS as a template object:
const FIELDS = {
id: null,
title: null,
contributor: null,
mediatype: null,
source: null
};
const normalize = items => items.map(item => ({...FIELDS, ...item}));
Your if (!item[f]) test will match on any falsy value, which is probably not what you want.
Instead, you should properly check if the key exists, e.g.:
if (!(f in item))
Not sure if this is any better really... but here is some equivalent alternative syntax.
Use an "equals itself or null" to squeeze out a bit more sugar:
const normalize = items =>
items.map(item => {
FIELDS.forEach(f => item[f] = item[f] || null);
return item;
});
Or test everyone's patience with this one liner:
const normalize = items =>
items.map(item => FIELDS.reduce((acc, field) => {acc[field] = item[field] || null; return acc}, item));
The choice is yours.
I have an array like this:
[
{
"id": 10002,
"flag": false,
"list": [
"aaa",
"bbb"
]
},
{
"id": 10001,
"flag": true,
"list": [
"10002",
"10003"
]
},
{
"id": 10003,
"flag": false,
"list": [
"ccc",
"ddd"
]
}
]
i tried this
initially i have "10001" value so iterate this array to take "list" array if flag==true then stored into newarray. but its not working.
I want it to be like this: [ "aaa", "bbb", "ccc", "ddd" ].
If i understand correctly this is what you want:
const someArray = [
{
"id": 10001,
"list": [
"10002",
"10003"
]
},
{
"id": 10002,
"list": [
"aaa",
"bbb"
]
},
{
"id": 10003,
"list": [
"ccc",
"ddd"
]
}
];
const [head,...rest] = someArray;
const result = head.list.reduce((acc,currentId)=>acc.concat(rest.find(({id})=> id === parseInt(currentId)).list),[]);
Here is a jsFiddle https://jsfiddle.net/sudakatux/9hju85mt/22/
Explanation:
take the head and splitted from the rest since the head contains the ids.
using the head as a dictionary find each list for each id in the head and concatenate
note the id must be in the subsequent list else it will fail with undefined. if you want to account for this error you can set a defualt empty object with a list. for example this part:
rest.find(({id})=> id === parseInt(currentId)).list
Will look like
rest.find(({id})=> id === parseInt(currentId)) || {list:[]}).list
Which basically means if its undefined return an object that has an empty list so then it will concatenate an empty list which results in being the same list. (like multiplying by 1 in a multiplication)
Hope it helps.
EDIT after your edit.
If your array is in different order you need to find the dictonary and then the logic is the same
const [newHead] = otherArray.filter(({list}) => list.every(elem=>!isNaN(elem)));
const result2 = newHead.list.reduce(
(acc,currentId) =>acc.concat(otherArray.find(({id})=> id === parseInt(currentId)).list),[]);
if you are testing for the flag then your head filter would look like. the blocks are the same the only thing that changes is the condition.
const [newHead] = otherArray.filter(({flag}) => flag));
(note* that instead of using the rest i used the complete array(otherArray). since im targeting equality.
Im using filter and extracting the first element of the result. because im accounting for the possibility that in the future you may have more than one "dictionary element". if thats the case in the future then you just have to concat the lists from the filter result
const array = [
{
id: 10001,
flag: true,
list: ["10002", "10003"]
},
{
flag: false,
id: 10002,
list: ["aaa", "bbb"]
},
{
flag: false,
id: 10003,
list: ["ccc", "ddd"]
}
];
const isHead = item => item.flag && item.id === 10001;
const head = array.find(isHead);
const rest = array.filter(item => !isHead(item));
const result = rest
.flatMap(item =>
head.list.includes(item.id.toString()) && item.list
);
console.log(result);
You can map over the list of the first item and concat all the lists from those ids.
const mapItems = (input) => {
const source = input[0].list;
source.reduce((results, id) => {
return results.concat(input.find(item => item.id === id).list);
}, []);
};
mapItems([
{
"id": 10001,
"list": [
"10002",
"10003"
]
},
{
"id": 10002,
"list": [
"aaa",
"bbb"
]
},
{
"id": 10003,
"list": [
"ccc",
"ddd"
]
}
]);
You can fetch the values of the list of first object in the array as arr[0]['list']
Once you have these values (10002,10003) then you can fetch the list values of remaining objects in the array whose id key matches one of the above values.
if(arr[i]['id'] == 10002 || arr[i]['id'] == 10003){
//fetch the list values
}
I want to use Lodash chain function to filter through an arrays nested array items and then return the full parent object.
Here is some dummy data from my use case to illustrate my issue:
const capital = [
{
"financeCategory": "Loans",
"financeCategoryId": "22HM6fFFwx9eK2P42Onc",
"financeElements": [
{
"financeCategoryId": "22HM6fFFwx9eK2P42Onc",
"financeElementId": "JQiqqvGEugVQuI0fN1xQ",
"financeElementTitle": "Convertible loan",
"data": [
{
"month": 1,
"value": 100,
"year": "2020"
},
{
"month": 1,
"value": 100,
"year": "2019"
},
],
}
]
},
{
"financeCategory": "Investments",
"financeCategoryId": "JtnUsk5M4oklIFk6cAlL",
"financeElements": []
},
{
"financeCategory": "Ownerships Contribution",
"financeCategoryId": "PaDhGBm5uF0PhKJ1l6WX",
"financeElements": []
}
];
I want to filter on the "data" array within the financeElements and then return full expense object with the filter applied on "data".
Let's say I want to manipulate the expense object and only get the data on the financeElements that have the year 2020. I've tried like so:
const expenseFiltered: any = _.chain(expenses)
.flatMap('financeElements')
.flatMap('data')
.filter({year: '2020' as any}).value();
But that just gives me the filtered "data" objects.
Output:
[{
"month": 1,
"value": 100,
"year": "2020"
}]
Now I know there are ways that I could use that to produce the full object with the filtered data, but I really want to do this in just one simple _.chain command
Desired output
[
{
"financeCategory": "Loans",
"financeCategoryId": "22HM6fFFwx9eK2P42Onc",
"financeElements": [
{
"financeCategoryId": "22HM6fFFwx9eK2P42Onc",
"financeElementId": "JQiqqvGEugVQuI0fN1xQ",
"financeElementTitle": "Convertible loan",
"data": [
{
"month": 1,
"value": 100,
"year": "2020"
}
],
}
]
},
{
"financeCategory": "Investments",
"financeCategoryId": "JtnUsk5M4oklIFk6cAlL",
"financeElements": []
},
{
"financeCategory": "Ownerships Contribution",
"financeCategoryId": "PaDhGBm5uF0PhKJ1l6WX",
"financeElements": []
}
]
Is this possible using lodash chain?
A chain is used to transform a structure in several steps. In your case, you don't want to change the structure. You can use nested Array.map() (or lodash's _.map()) calls to iterate and rebuild the structure, and internally _.filter() the data:
const capital = [{"financeCategory":"Loans","financeCategoryId":"22HM6fFFwx9eK2P42Onc","financeElements":[{"financeCategoryId":"22HM6fFFwx9eK2P42Onc","financeElementId":"JQiqqvGEugVQuI0fN1xQ","financeElementTitle":"Convertible loan","data":[{"month":1,"value":100,"year":"2020"},{"month":1,"value":100,"year":"2019"}]}]},{"financeCategory":"Investments","financeCategoryId":"JtnUsk5M4oklIFk6cAlL","financeElements":[]},{"financeCategory":"Ownerships Contribution","financeCategoryId":"PaDhGBm5uF0PhKJ1l6WX","financeElements":[]}];
const expenseFiltered = capital.map(ex => ({
...ex,
financeElements: ex.financeElements.map(fe => ({
...fe,
data: _.filter(fe.data, { year: '2020' })
}))
}));
console.log(expenseFiltered);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>