I have a problem with how to compare value to get largest number in more than one object.
For example i have 3 object (and this object can increment more than 3):
These each object saved in acc variable
[
{ "key": 1, "value": 1 },
{ "key": 1, "value": 3 },
{ "key": 1, "value": 6 },
]
[
{ "key": 2, "value": 2 },
{ "key": 2, "value": 5 },
{ "key": 2, "value": 9 },
]
[
{ "key": 3, "value": 1 },
{ "key": 3, "value": 2 },
{ "key": 3, "value": 3 },
]
First i get the last value from each object with console.log(acc[acc.length - 1].value);
and it will print:
6
9
2
Then i don't know how to compare the numbers? And get result:
{ "key": 2, "value": 9 }
I have try console.log(Math.max(acc[acc.length - 1].value));, but its not working because that number is not inside one array.
This is screenshot if i log console.log(acc)
First merge all the nested objects by .flat() and perform .reduce() operation on them. in every iteration look b.value is greater than the object value of accumulator a.value, if it's the case we need to update the object of the accumulator a.
const arr = [[ { "key": 1, "value": 1 }, { "key": 1, "value": 3 }, { "key": 1, "value": 6 }, ], [ { "key": 2, "value": 2 }, { "key": 2, "value": 5 }, { "key": 2, "value": 9 }, ], [ { "key": 3, "value": 1 }, { "key": 3, "value": 2 }, { "key": 3, "value": 3 }, ]];
console.log(arr.flat().reduce((a,b)=>(b.value > a.value ? b : a)));
New requirement:
const arr = [[
{ "key": 1, "value": 1 },
{ "key": 1, "value": 3 },
{ "key": 1, "value": 6 },
{ "key": 3, "value": 6 },
],
[
{ "key": 2, "value": 2 },
{ "key": 2, "value": 5 },
{ "key": 2, "value": 9 },
],
[
{ "key": 3, "value": 1 },
{ "key": 3, "value": 2 },
{ "key": 3, "value": 3 },
]];
let results = [{key: -1, value: -1}]; //initial value I assume data don't have a value less than -1
arr.forEach((item) => { //Simulating your current situation
item.forEach(it => { //here we get an array in each iteration
if (it.value > results[0].value) {
results = [it];
}
else if (it.value === results[0].value) {
results.push(it);
}
});
});
console.log(results);
Related
I have an array of subscriptions group by the type (basic,medium ...)
`
[
[
"Basic",
[
{ "id": 2, "name": "Basic", "started_at": "2022-01-24", "count": 4 },
{ "id": 2, "name": "Basic", "started_at": "2022-03-16", "count": 2 },
{ "id": 2, "name": "Basic", "started_at": "2022-05-16", "count": 1 }
]
],
[
"Medium",
[
{ "id": 3, "name": "Medium", "started_at": "2022-02-21", "count": 1 },
{ "id": 3, "name": "Medium", "started_at": "2022-05-28", "count": 1 }
]
],
[
"Premium",
[{ "id": 4, "name": "Premium", "started_at": "2022-04-21", "count": 1 }]
],
[
"Master",
[
{ "id": 7, "name": "Master", "started_at": "2022-07-28", "count": 1 },
{ "id": 7, "name": "Master", "started_at": "2022-08-02", "count": 1 }
]
],
[
"Jedi",
[{ "id": 6, "name": "Jedi", "started_at": "2022-09-28", "count": 1 }]
]
]
`
What I want to do is return an array containing objects foreach sub with the following data(get the count value by month):
`
[
{
label: "Basic",
data: [4, 0, 2, 0, 1,0],
},
{
label: "Medium",
data: [0, 1, 0, 0, 1,0],
},
...
]
`
The data field should contain the count field foreach subscription corresponding to the month. For example for with count 4 in January and count 2 in March it will return [4,0,1] with 0 for February.
How can I achieve that ?
I did this but it's returning only the existing month values so there is no way to know which month that value is for.
subscriptions.map((item) => {
return {
label: item[0],
data: item[1].map((value, index) => {
return value.count;
}),
};
})
You could reduce the array and create a mapper object which maps each plan with month specifc count. Something like this:
{
"Basic": {
"1": 4,
"3": 2,
"5": 1
},
"Medium": {
"2": 1,
"5": 1
},
...
}
Then loop through the entries of the object and create objects with plan as label and an array of length: 12 and get the data for that specific month using the index
const input=[["Basic",[{id:2,name:"Basic",started_at:"2022-01-24",count:4},{id:2,name:"Basic",started_at:"2022-03-16",count:2},{id:2,name:"Basic",started_at:"2022-05-16",count:1}]],["Medium",[{id:3,name:"Medium",started_at:"2022-02-21",count:1},{id:3,name:"Medium",started_at:"2022-05-28",count:1}]],["Premium",[{id:4,name:"Premium",started_at:"2022-04-21",count:1}]],["Master",[{id:7,name:"Master",started_at:"2022-07-28",count:1},{id:7,name:"Master",started_at:"2022-08-02",count:1}]],["Jedi",[{id:6,name:"Jedi",started_at:"2022-09-28",count:1}]]];
const mapper = input.reduce((acc, [plan, subscriptions]) => {
acc[plan] ??= {}
for(const { started_at, count } of subscriptions)
acc[plan][+started_at.slice(5,7)] = count
return acc;
}, {})
const output =
Object.entries(mapper)
.map( ([label, subData]) => ({
label,
data: Array.from({ length: 12 }, (_, i) => subData[i+1] ?? 0)
}) )
console.log(output)
Note:
This assumes that the data is for a single year only. If it can be across years you'd have to create another level of nesting:
{
"Basic": {
"2022": {
"1": 3
}
}
}
started_at.slice(5,7) is used to get the month number. If the dates are not in the ISO 8601 format, you can use new Date(started_at).getMonth() + 1 to get the month part.
I have 2 arrays of objects
array1 = [
{
"name": "B",
"order": 1
},
{
"name": "C",
"order": 2
},
{
"name": "D",
"order": 3
},
{
"name": "B",
"order": 4
},
{
"name": "A",
"order": 5
}
]
array2 = [
{
"name": "B",
"order": 1,
"id": 3638
},
{
"name": "B",
"order": 1,
"id": 3661
},
{
"name": "C",
"order": 2,
"id": 3658
},
{
"name": "D",
"order": 3,
"id": 3659
},
{
"name": "A",
"order": 5,
"id": 3636
}
]
I need to sort array2 to match the same order of array1 based on the property name.
In array2 there are 2 names properties equal with value B.
These name B are together but i need the array to be in the exact order of array1.
In array1 the first B is at index 0 and the second B is at index 3.
I made this attempts without luck.
array2.sort((a, b) => array1.indexOf(a.name) - array1.indexOf(b.name));
let sorted = array2.sort((a, b) => {
return array1.findIndex(p => p.name=== a.name) - array1.findIndex(p => p.name=== b.name);
});
You can try this, it finds the first elem in array2 matching the name, in order, from the array1.. removes it from array2 and then adds it to the sortedArray2.
const array1 = [
{
"name": "B",
"order": 1
},
{
"name": "C",
"order": 2
},
{
"name": "D",
"order": 3
},
{
"name": "B",
"order": 4
},
{
"name": "A",
"order": 5
}
]
const array2 = [
{
"name": "B",
"order": 1,
"id": 3638
},
{
"name": "B",
"order": 1,
"id": 3661
},
{
"name": "C",
"order": 2,
"id": 3658
},
{
"name": "D",
"order": 3,
"id": 3659
},
{
"name": "A",
"order": 5,
"id": 3636
}
]
const sortedArray2 = []
for(const item of array1) {
sortedArray2.push(
array2.splice(
array2.findIndex(elem => elem.name === item.name), 1
)
)
}
console.log(sortedArray2)
This question already has answers here:
Group objects by property in javascript
(8 answers)
Closed 2 years ago.
let attributeSet = [{
"id": 1,
"value": 11
},
{
"id" : 1,
"value": 12
},
{
"id" : 1,
"value" : 13
},
{
"id": "2",
"value" : "Qwerty"
}
]
I want to combine all the value in values like this
attributeSet = [
{
"id": 1,
"value": [11, 12, 13]
},
{
"id": 2,
"value": "Qwerty"
}
]
I am using two for loops for comparing the ids and then pushing it into an array. Can someone suggest me any better way.
You can use reduce & inside callback check if the accumulator object have the key same as id of the object under iteration. If not then create the key and push value to it
let attributeSet = [{
"id": 1,
"value": 11
},
{
"id": 1,
"value": 12
},
{
"id": 1,
"value": 13
},
{
"id": "2",
"value": "Qwerty"
}
]
let newData = attributeSet.reduce((acc, curr) => {
if (!acc[curr.id]) {
acc[curr.id] = {
id: curr.id,
value: []
}
}
acc[curr.id].value.push(curr.value)
return acc;
}, {});
console.log(Object.values(newData))
I want to show the Object wordCounts,which stores a series of words with a value that is the number of times a word is repeated in a string, what happens is that I want to show that variable in order by the number of repetitions that word has, and I just want the 20 most repeated words to be shown. The main problem I have is that as far as I have the code it returns a JSON, which does not allow me to put in a div to give it a style.
project-details.ts
getWordCount(str) {
let arrayOfWords = str.split(/\s+/);
var wordCounts = Object.create(null);
for(let i = 0; i<arrayOfWords.length; i++){
let word = arrayOfWords[i];
if(!wordCounts[word]){
wordCounts[word] = 1;
}else{
wordCounts[word] ++;
}
}
return wordCounts;
};
project-details.html
<p>{{getWordCount(str) | keyvalue | json}}</p>
representation
[ { "key": "También", "value": 1 }, { "key": "Un", "value": 1 }, { "key": "algoritmo", "value": 1 }, { "key": "aunque", "value": 1 }, { "key": "caracteres", "value": 1 }, { "key": "cifrado", "value": 1 }, { "key": "codificados", "value": 1 }, { "key": "composición", "value": 2 }, { "key": "cualquier", "value": 1 }, { "key": "de", "value": 5 }, { "key": "descifrado", "value": 1 }, { "key": "destinatario", "value": 1 }, { "key": "en", "value": 1 }, { "key": "es", "value": 2 }, { "key": "escritura", "value": 1 }, { "key": "forma", "value": 1 }, { "key": "generados", "value": 1 }, { "key": "imprimibles", "value": 1 }, { "key": "no", "value": 1 }, { "key": "original.", "value": 1 }, { "key": "para", "value": 1 }, { "key": "persona,", "value": 1 }, { "key": "por", "value": 2 }, { "key": "puede", "value": 1 }, { "key": "que", "value": 1 }, { "key": "que,", "value": 1 }, { "key": "sentido", "value": 1 }, { "key": "sentido.", "value": 1 }, { "key": "ser", "value": 1 }, { "key": "signos", "value": 1 }, { "key": "sistema", "value": 1 }, { "key": "su", "value": 1 }, { "key": "sí", "value": 1 }, { "key": "texto", "value": 1 }, { "key": "tienen", "value": 1 }, { "key": "un", "value": 2 }, { "key": "una", "value": 3 }, { "key": "unidad", "value": 1 } ]
And with that result I can't give it any style.
You could assign the value to a variable, remove the json pipe and loop the value directly in the HTML. Try the following
Controller
export class WordComponent {
wordCount: any;
getWordCount(str) {
let arrayOfWords = str.split(/\s+/);
let wordCounts = Object.create(null);
for(let i = 0; i < arrayOfWords.length - 1; i++){
let word = arrayOfWords[i];
wordCounts[word] ? wordCounts[word]++ : wordCounts[word] = 1;
}
return wordCounts;
};
onMouseUp(str: string) {
this.wordCount = this.getWordCount(str);
}
}
Template
<button (mouseup)="onMouseUp('str')">Get word count</button>
<ng-container *ngIf="wordCount">
<p class="style" *ngFor="let word of wordCount | keyvalue">{{ word.key }} : {{ word.value }}</p>
</ng-container>
You can then modify and render as per you wish. Also note the loop condition should be arrayOfWords.length - 1 because index starts from zero.
It sounds like what you need is a ShowWordCounts component which takes your object as an #Input and generates the corresponding template.
As per my original question geared specifically for React (React recursive tree pass JSON path), I have realised the problem is pretty generic.
I have a recursive function that essentially loops through a treelike JSON structure, each time it outputs a branch I want to pass an object of the structures location in the tree like below.. Is there a simpler way to pass the structure? Is the data structure poor / should each chid have a unique ID attached?
My JSON object is below so you can see what I'm working with.
Any help much appreciated!
Level 1 child
{value: "Fruit"}
Level 2 child
{value: "Fruit", nested_values: [{ value: 'Tropical'}] }
Level 3 child
{value: "Fruit", nested_values: [{ value: 'Tropical', nested_values:[{ value: 'Pineapple' }]}] }
Code - kind of works, but then I get all values within the same nested_values array
const createSelectionHierarchy = (data, isSub, level = 2, hierarchy = {}) => {
let children = [];
if (isSub) { level++; }
let obj = {};
obj.name = cat;
const cat = hierarchy.value;
for (let i in data) {
const subcat = data[i].value;
if (typeof(data[i].nested_values) === 'object') { // Sub array found, build structure
obj.values = subcat;
obj.nested_values = [];
hierarchy.nested_values.push(obj);
children.push(
<FilterItem key={i} data={data[i]} hierarchy={hierarchy} level={level}>
{createSelectionHierarchy(data[i].nested_values, true, level, hierarchy)}
</FilterItem>
);
} else { // No sub array, bottom of current branch
children.push(
<p className="filter-item level-last" key={i}>
{data[i].value}
</p>);
}
}
return children;
}
JSON
{
"value": "Fruit",
"occurrence_count": 5,
"nested_values": [{
"value": "Berries",
"occurrence_count": 3,
"nested_values": [{
"value": "Strawberry",
"occurrence_count": 1
}, {
"value": "Blackberry",
"occurrence_count": 1
}, {
"value": "Raspberry",
"occurrence_count": 1
}, {
"value": "Redcurrant",
"occurrence_count": 1
}, {
"value": "Blackcurrant",
"occurrence_count": 1
}, {
"value": "Gooseberry",
"occurrence_count": 1
}, {
"value": "Cranberry",
"occurrence_count": 1
}, {
"value": "Whitecurrant",
"occurrence_count": 1
}, {
"value": "Loganberry",
"occurrence_count": 1
}, {
"value": "Strawberry",
"occurrence_count": 1
}]
}, {
"value": "Tropical",
"occurrence_count": 2,
"nested_values": [{
"value": "Pineapple",
"occurrence_count": 1
}, {
"value": "Mango",
"occurrence_count": 1
}, {
"value": "Guava",
"occurrence_count": 1
}, {
"value": "Passion Fruit",
"occurrence_count": 1
}, {
"value": "Dragon Fruit",
"occurrence_count": 1
}]
}]
}
Desired output
<FilterItem ...... hierarchy={{value: "Fruit"}}>
<FilterItem ...... hierarchy={{value: "Fruit", nested_values: [{ value: 'Tropical'}] }}>
<FilterItem ...... hierarchy={{value: "Fruit", nested_values: [{ value: 'Tropical', nested_values:[{ value: 'Pineapple' }]}] }}>
</FilterItem>
</FilterItem>
</FilterItem>
For each branch (level of tree), this function will extract the value and then call itself on each of its children, if there are any, and store their return values in an array.
function convert(branch) {
const hierarchy = {
value: branch.value
};
if (branch.nested_values !== undefined)
hierarchy.nested_values = branch.nested_values.map(subranch => convert(subranch))
return hierarchy;
}
const input = {
"value": "Fruit",
"occurrence_count": 5,
"nested_values": [{
"value": "Berries",
"occurrence_count": 3,
"nested_values": [{
"value": "Strawberry",
"occurrence_count": 1
}, {
"value": "Blackberry",
"occurrence_count": 1
}, {
"value": "Raspberry",
"occurrence_count": 1
}, {
"value": "Redcurrant",
"occurrence_count": 1
}, {
"value": "Blackcurrant",
"occurrence_count": 1
}, {
"value": "Gooseberry",
"occurrence_count": 1
}, {
"value": "Cranberry",
"occurrence_count": 1
}, {
"value": "Whitecurrant",
"occurrence_count": 1
}, {
"value": "Loganberry",
"occurrence_count": 1
}, {
"value": "Strawberry",
"occurrence_count": 1
}]
}, {
"value": "Tropical",
"occurrence_count": 2,
"nested_values": [{
"value": "Pineapple",
"occurrence_count": 1
}, {
"value": "Mango",
"occurrence_count": 1
}, {
"value": "Guava",
"occurrence_count": 1
}, {
"value": "Passion Fruit",
"occurrence_count": 1
}, {
"value": "Dragon Fruit",
"occurrence_count": 1
}]
}]
};
function convert(branch) {
const hierarchy = {
value: branch.value
};
if (branch.nested_values !== undefined)
hierarchy.nested_values = branch.nested_values.map(subranch => convert(subranch))
return hierarchy;
}
console.log(convert(input));
On a side note, what you supplied is not valid JSON (keys mustn't have quotes), it is a JavaScript object. To get an object from a JSON string, you have to call JSON.parse().