How to add <hr> after every new category - javascript

I have a array of object called elements, and the objects have two values (name and category).
[
{name : 'key1', category : 'tech'},
{name : 'key2', category : 'tech'},
{name : 'key3', category : 'tech'},
{name : 'cable1' , category : 'hard'}
{name : 'cable2' , category : 'hard'}
{name : 'cable3' , category : 'hard'}
{name : 'cable4' , category : 'hard'}
]
I want to display all names but add an <hr> whenever reaches a new category
Please help and thank you of helping.

I would first group your objects by category using Array.prototype.reduce(), then iterate over each category using Array.prototype.map():
const data = [
{name : 'key1', category : 'tech'},
{name : 'wire1' , category : 'misc'},
{name : 'key2', category : 'tech'},
{name : 'cable1' , category : 'hard'},
{name : 'key3', category : 'tech'},
{name : 'cable2' , category : 'hard'},
{name : 'wire2' , category : 'misc'}
];
const dataMap = data.reduce((acc, x) => {
acc[x.category] = [...(acc[x.category] || []), x];
return acc;
}, {});
const html = Object.entries(dataMap).map(([cat, items]) => {
return items.map(item => `<div>${item.name} ${item.category}</div>`).join('');
}).join('<hr>');
document.getElementById('app').innerHTML = html;
<div id="app"></div>

You can try something like this,
var category;
$.each(object,function(i,objval)
{
console.log(objval['name']);
if(category != "" && category != objval['category'])
{
console.log("<hr>");
}
category = objval['category'];
});

How about something like:
prev_category = undefined;
elements.forEach(function(e) {
if (i > 0 && e.category != prev_category) {
console.log('<hr>');
}
prev_category = e.category;
console.log(e.name);
});
(of course, you can replace the console.log() commands with whatever you really want to do with those texts, e.g. append them to one big string)

Iterate the object and use template literals to create the dom and check if the index of the array is not same as length then add an hr
let elements = [{
name: 'key',
category: 'tech'
},
{
name: 'cable',
category: 'hard'
}
]
let str = '';
elements.forEach(function(item, index) {
str += `<div class='elem'><span>${item.name}</span><span> ${item.category}</span></div>`
if (index !== elements.length - 1) {
str += `<hr>`
}
});
document.getElementById('container').innerHTML = str
<div id='container'></div>
If you are looking for just border then use css pseudo selector
let elements = [{
name: 'key',
category: 'tech'
},
{
name: 'cable',
category: 'hard'
}
]
let str = '';
elements.forEach(function(item, index) {
str += `<div class='elem'><span>${item.name}</span><span> ${item.category}</span></div>`
});
document.getElementById('container').innerHTML = str
.elem:not(:last-child) {
border-bottom: 1px solid black;
}
<div id='container'></div>

Basically you need to sort the data by category first then, render the element, I use react code as example
const data = [
{
name: "Huawei",
category: "phone"
},
{
name: "Iphone",
category: "phone"
},
{
name: "Refacoring Improving the design of existing code",
category: "book"
},
{
name: "Python Crash Course",
category: "book"
},
{
name: "My heart will go on",
category: "music"
},
{
name: "I'm your angel",
category: "music"
}
];
function generateCom(data) {
let listComps = [];
let category = "";
// sort the data by category
data.sort((a, b) => (a.category > b.category ? 1 : -1));
// generate the component by category
data.forEach((ele, idx) => {
if (idx === 0) {
listComps.push(<h3>{ele.category}</h3>);
listComps.push(<li>{ele.name}</li>);
category = ele.category;
return;
}
if (ele.category === category) {
listComps.push(<li>{ele.name}</li>);
} else {
listComps.push(<hr />);
listComps.push(<h3>{ele.category}</h3>);
listComps.push(<li>{ele.name} </li>);
category = ele.category;
}
});
return listComps;
}
can refer to the example
https://codesandbox.io/embed/6x0p7908qw

Related

I have an array of object which needs to restructured into a desired format. I tried using array destructuring using iteration

The desired output should be as follows. I tried object restructuring way but i could not push the out as an object. If you can just guide me what are the other array methods i can use to get the desired array
const sample = [
{
name: 'Bike',
series: [
{ date: '01-01-2020', value: '4$' },
{ date: '02-01-2020', value: '3$' },
{ date: '03-01-2020', value: '3.5$' }
]
},
{
name: 'Watch',
series: [
{ date: '01-01-2020', value: '1$' },
{ date: '02-01-2020', value: '2$' },
{ date: '03-01-2020', value: '5$' }
]
}
]
const output = [
{ date: '01-01-2020', 'bike-value': '4$', 'watch-value': '1$' },
{ date: '02-01-2020', 'bike-value': '3$', 'watch-value': '2$' },
{ date: '03-01-2020', 'bike-value': '3.5$', 'watch-value': '5$'}
]
What i tried is as follows. But i cannot make this into a object to push into an empty array.
for (const {name: n, series: [{date: d , value: v}]} of sample) {
console.log('name: ' + n + ', date: ' + d + ', value: ' + v);
}
You could loop through the sample array and then loop through the each series array. Create a group object which has each date as key and the object needed in the final output it's value. Use Object.values() to get the values of the group object as an array
const sample=[{name:"Bike",series:[{date:"01-01-2020",value:"4$"},{date:"02-01-2020",value:"3$"},{date:"03-01-2020",value:"3.5$"}]},{name:"Watch",series:[{date:"01-01-2020",value:"1$"},{date:"02-01-2020",value:"2$"},{date:"03-01-2020",value:"5$"}]}];
const group = {}
for (const { name, series } of sample) {
for (const { date, value } of series) {
group[date] = group[date] || { date };
group[date][`${name.toLowerCase()}-value`] = value
}
}
const output = Object.values(group)
console.log(output)
The group object looks like this:
{
"01-01-2020": {
"date": "01-01-2020",
"bike-value": "4$",
"watch-value": "1$"
},
"02-01-2020": {
"date": "02-01-2020",
"bike-value": "3$",
...
},
"03-01-2020": {
....
}
A simple nested constructor should work here:
const sample = [
{name : 'Bike', series :
[{date : '01-01-2020', value : '4$'},
{date : '02-01-2020', value : '3$'},
{date : '03-01-2020', value : '3.5$'}]
},
{name : 'Watch', series :
[{date : '01-01-2020', value : '1$'},
{date : '02-01-2020', value : '2$'},
{date : '03-01-2020', value : '5$'}]
}
];
let results = [];
for (let i = 0; i< sample[0].series.length; i++){
//get date and 'Bike' value from first value
let newEntry = {date : sample[0].series[i].date, bikeValue : sample[0].series[i].value};
//find the corresponding 'Watch' value with another loop
let watchValue = 0;
for (let i2 = 0; i2<sample[1].series.length; i2++){
if(sample[1].series[i2].date == newEntry.date){
watchValue = sample[1].series[i2].value;
}
}
newEntry.watchValue = watchValue;
//push new object into results array
results.push(newEntry);
}
console.log(results);

Generating Entries with Same Name in JavaScript Object

I'm new to Javascript and I've done a little research but I can't seem to figure out how to generate multiple lists with same name keys but different values. I'm trying to generate code for an embed message which should look something like this:
{embed: {
color: 3447003,
title: "title",
description: "desc",
fields: [{
name: "header 1",
value: "text 1"
},
{
name: "header 2",
value: "text 2"
},
{
name: "header 3",
value: "text 3"
}
]
}
}
this is for generating a list of my commands in an embed automatically so I don't have to keep going back and edit it.
I'm mainly trying to get multiple of the "fields" with the "name" and "value" entries and also trying to add all the commands in a line for the "value".
Here's my code:
let currentCategory = "";
var embed = {
"title": "= __Command List__ =",
"description": `[Use ${message.settings.prefix}help <commandname> for details]`,
"color": 2563607,
fields : []
};
const sorted = myCommands.array().sort((p, c) => p.help.category > c.help.category ? 1 : p.help.name > c.help.name && p.help.category === c.help.category ? 1 : -1 );
sorted.forEach( c => {
const cat = c.help.category.toProperCase();
if (currentCategory !== cat) {
embed.fields = [{name : `${cat}`,value : ""}];
currentCategory = cat;
}
embed.fields[0].value += ` \`${c.help.name}\``;
});
console.log({embed});
message.channel.send({embed});
I used console.log({embed}); to print the code it generates in the console and this is what shows.
{ embed:
{ title: '= __Command List__ =',
description: '[Use y!help <commandname> for details]',
color: 2563607,
fields: [ [Object] ] } }
Ok I figured it out thanks to PM 77-1.
For anyone else who wants to know I basically set and index of -1 and made it add to the index while it looped for every new category.
let currentCategory = "";
let index = -1;
var embed = {
"title": "= __Command List__ =",
"description": `[Use ${message.settings.prefix}help <commandname> for details]`,
"color": 2563607,
fields : []
};
const sorted = myCommands.array().sort((p, c) => p.help.category > c.help.category ? 1 : p.help.name > c.help.name && p.help.category === c.help.category ? 1 : -1 );
sorted.forEach( c => {
const cat = c.help.category.toProperCase();
if (currentCategory !== cat) {
index = index + 1
embed.fields[index] = {name : `${cat}`,value : ""};
currentCategory = cat;
}
embed.fields[index].value += ` \`${c.help.name}\``;
});
console.log({embed});
message.channel.send({embed});

How can I remove duplicates in an array of object?

I have an array which looks like this :
var array =
[
{
key : { id : 1 , pack : "pack 1"},
values : [
{
item : { id : 1 , name : "item1"},
itemP : {id : 2 , name : "itemP12"}
},
{
item : { id : 4 , name : "item4"},
itemP : {id : 2 , name : "itemP12"}
},
]
}
]
I want to remove duplicate itemP so with a function it will look like this :
var array =
[
{
key : { id : 1 , pack : "pack 1"},
values : [
{
item : { id : 1 , name : "item1"},
itemP : {id : 2 , name : "itemP12"}
},
{
item : { id : 4 , name : "item4"},
itemP : null
},
]
}
]
When I try I always have errors. It is possible to do this?
Update
I try to do this :
console.log(array.map(pack =>
pack.values.map((item) => {
var test = JSON.stringify(item)
var set = new Set(test)
return Array.from(set).map((item)=> JSON.parse(item))
}
)
))
Unexpected end of JSON input
I also try something will filter but it doesn't work:
console.log(this.package.map(pack => pack.values.filter(
(value, index , array) => array.itemP.indexOf(value) === index
)))
Instead of mapping every key property, I suggest cloning the whole structure and setting the object value as null in the cloned one, avoiding unintentionally mutating the original structure.
function nullifyDupes(array) {
const clone = JSON.parse(JSON.stringify(array));
const seen = {};
clone.forEach(pack => {
pack.values.forEach(items => {
for (const item in items) {
const id = items[item].id;
if (seen[id]) items[item] = null;
else seen[id] = true;
}
});
});
return clone;
}
const originalArray = [{
key : { id : 1 , pack : "pack 1"},
values : [{
item : { id : 1 , name : "item1"},
itemP : {id : 2 , name : "itemP12"}
},
{
item : { id : 4 , name : "item4"},
itemP : {id : 2 , name : "itemP12"}
}]
}];
const mutatedArray = nullifyDupes(originalArray);
console.log(mutatedArray);
To achieve expected result, use below option of using map
Loop array using map
Use nameArr to check duplicate and assigning null value
Loop values array and check the name in nameArr using indexOf and assign null
var array = [
{
key : { id : 1 , pack : "pack 1"},
values : [
{
item : { id : 1 , name : "item1"},
itemP : {id : 2 , name : "itemP12"}
},
{
item : { id : 4 , name : "item4"},
itemP : {id : 2 , name : "itemP12"}
}
]
}
]
console.log(array.map(v => {
let nameArr = []
v.values = v.values.map(val => {
if(nameArr.indexOf(val.itemP.name) !== -1){
val.itemP.name = null
}else{
nameArr.push(val.itemP.name)
}
return val
})
return v
}))
You can use map and an object to check if its already exist. Like
var obj = {}
and loop over values
var values = [
{
item : { id : 1 , name : "item1"},
itemP : {id : 2 , name : "itemP12"}
},
{
item : { id : 4 , name : "item4"},
itemP : {id : 2 , name : "itemP12"}
}
]
values.map((v) => {
if(!obj[v.itemP.id + '-' + v.itemP.name]) {
obj[v.itemP.id + '-' + v.itemP.name] = true;
return v;
}
return { item : v.item }
})
You can map your array elements to array objects which don't include your duplicates using .map(). For each iteration of .map() you can again use .map() for your inner values array to convert it into an array of objects such that the duplicates are converted to null. Here I have kept a seen object which keeps track of the properties seen and their stringified values. By looping over all the properties in your object (using for...of), you can work out whether or not the key-value pair has been seen before by using the seen object.
The advantage of this approach is that it doesn't just work with one property (ie not just itemP), but it will work with any other duplicating key-value pairs.
See example below:
const array = [{key:{id:1,pack:"pack 1"},values:[{item:{id:1,name:"item1"},itemP:{id:2,name:"itemP12"}},{item:{id:4,name:"item4"},itemP:{id:2,name:"itemP12"}}]}];
const seen = {};
const res = array.map(obj => {
obj.values = obj.values.map(vobj => {
for (let p in vobj) {
vobj[p] = seen[p] === JSON.stringify(vobj[p]) ? null : vobj[p];
seen[p] = seen[p] || JSON.stringify(vobj[p]);
}
return vobj;
});
return obj;
});
console.log(res);
For an approach which just removed itemP from all object in accross your array you can use:
const array = [{key:{id:1,pack:"pack 1"},values:[{item:{id:1,name:"item1"},itemP:{id:2,name:"itemP12"}},{item:{id:4,name:"item4"},itemP:{id:2,name:"itemP12"}}]}];
let itemP = "";
const res = array.map(obj => {
obj.values = obj.values.map(vobj => {
vobj.itemP = itemP ? null : vobj.itemP;
if('itemP' in vobj) {
itemP = itemP || JSON.stringify(vobj.itemP);
}
return vobj;
});
return obj;
});
console.log(res);

group array of objects by property first letter

im struggling a little with this, been a while since ive coded javascript ... trying to convert this
items = {
"data": [
{
"name" : "john"
},
{
"name" : "james"
},
{
"name" : "joe"
},
{
"name" : "brian"
},
{
"name" : "bojan"
},
{
"name" : "billy"
},
{
"name" : "dean"
},
{
"name" : "darren"
},
{
"name" : "doug"
}
]
}
into this format
items = {
"data": [
{
letter: "j"
names : ["john", "james", "joe"]
},
{
letter: "b"
names : ["brian", "bojan", "billy"]
},
{
letter: "j"
names : ["dean", "darren", "doug"]
},
]
}
I've been trying to do this using reduce but not having much look.... is there a simpler way to to do it?
You can use reduce to create an object with the letters as keys from which you can extrapolate the array of objects you need by iterating over the object entries using map.
const items = {"data":[{"name":"john"},{"name":"james"},{"name":"joe"},{"name":"brian"},{"name":"bojan"},{"name":"billy"},{"name":"dean"},{"name":"darren"},{"name":"doug"}]};
// `reduce` over the data to produce an object
// with letter keys, and array values where the names are added
const obj = items.data.reduce((acc, c) => {
const letter = c.name[0];
acc[letter] = (acc[letter] || []).concat(c.name);
return acc;
}, {})
// `map` over the object entries to return an array of objects
items.data = Object.entries(obj).map(([letter, names]) => {
return { letter, names }
}).sort((a, b) => a.letter > b.letter);
console.log(items);
Vanilla javascript implementation:
const items = {
"data": [
{
"name" : "john"
},
{
"name" : "james"
},
{
"name" : "joe"
},
{
"name" : "brian"
},
{
"name" : "bojan"
},
{
"name" : "billy"
},
{
"name" : "dean"
},
{
"name" : "darren"
},
{
"name" : "doug"
}
]
}
const transformed = {
data:[]
}
const findByLetter = (letter) => (element) => element.letter === letter;
for(let i = 0; i < items.data.length; i++){
const letter = items.data[i].name.split("")[0];
const elIndex = transformed.data.findIndex(findByLetter(letter));
if(elIndex > -1){
transformed.data[elIndex].names.push(items.data[i].name);
}else{
transformed.data.push({
letter,
names: [items.data[i].name],
});
}
};
console.log(transformed);
Use one reduce():
const items = {"data":[{"name":"john"},{"name":"james"},{"name":"joe"},{"name":"brian"},{"name":"bojan"},{"name":"billy"},{"name":"dean"},{"name":"darren"},{"name":"doug"}]};
let res = items.data.reduce((acc, item) => {
let l = item.name[0];
if (acc.data.filter(e => e.letter == l)[0] === undefined) acc.data.push({'letter': l, names: [] });
acc.data.filter(e => e.letter == l)[0].names.push(item.name);
return acc;
}, {"data": []})
console.log(res)

How to find item from an object with Javascript?

I have my data object:
var elements = {
'element' : {
'name' : 'test',
'price' : '55'
},
'element' : {
'name' : 'letev',
'price': '223'
}
};
Now, I don't know how can I find each element by name for example.
I need to find element by name test, and then acces it's other parameters (price,..)
You must change elements to array:
var elements = [
{
'name' : 'test',
'price' : '55'
},
{
'name' : 'letev',
'price': '223'
}
];
function findElementByName(name, elementsForSearch) {
if (name) {
elementsForSearch.filter(function(elem){
return elem.name === 'name';
});
return elementsForSearch[0];
}
return {};
}
alert(findElementByName('test', elements).name)
Assuming your object was an array instead of the syntax you used:
var elements = [
{
'name' : 'test',
'price' : '55'
},{
'name' : 'letev',
'price': '223'
}
];
You can filter the element out like this:
searchName = 'test';
elements.filter(function(element){
return element.name == searchName;
});
This will only return the elements that have 'test' as name.
Or as a function:
function filterByName(array, namr){
array.filter(function(element){
return element.name == name;
});
}
Called like this:
array result = filterByName(elements, 'test');
In case you need to support IE 8 or lower, you can use a polyfill for Array.prototype.filter.
you can do that if your elements object was an array, i.e.
var elements = [{
'element' : {
'name' : 'test',
'price' : '55'
},
'element' : {
'name' : 'letev',
'price': '223'
}
}];
var price;
for (var i=0; i <elements.length; i++) {
if (elements[i].name === 'test') {
price = elements[i].price;
break;
}
}
Try with:
var elements = [
{
'name' : 'test',
'price' : '55'
},
{
'name' : 'letev',
'price': '223'
}
];
var search = 'letev';
for (var i = 0; i < elements.length; i++) {
if (elements[i].name == search) {
alert('found!');
break;
}
}
Or using Array.filter:
var search = 'letev';
var output = elements.filter(function(element) {
return element.name == search;
});
Try this
var List= (JObject)JsonConvert.DeserializeObject(jsonstring);
var result= List["element"].Children().Select(node => node["name"]== "Test").ToList();

Categories