Unique Array by comparing elements of array React JS - arrays

I have this array
array = [
{id: "one", title: "new 1"},
{id: "two", parent_id: "132132", title: "new 2"},
{id: "three", parent_id: "132132", title: "new 3"},
{id: "four", parent_id: "132132", title: "new 1"},
{id: "one", parent_id: "132132", title: "new 1"}
]
We need
array = [
{id: "two", parent_id: "132132", title: "new 2"},
{id: "three", parent_id: "132132", title: "new 3"},
{id: "four", parent_id: "132132", title: "new 1"},
{id: "one", parent_id: "132132", title: "new 1"}
]
We need to compare elements to get unique array with different avoiding other elements
I have tried using this method
uniqueArray = (arr) => {
return arr.filter((e, i, arr) => arr.findIndex(e2 => Object.keys(e2).every(prop => e2[prop] === e[prop])) === i);
};

I prefer Array.reduce for this kind of things:
const filteredArr = arr.reduce((acc, current) => {
const exists = acc.find(item => item.id === current.id);
if (!exists) {
return acc.concat([current]);
} else {
return acc;
}
}, []);

If I understand you correctly, you want to return object without the property of parentId. If so you can use this.
array.filter(arr => arr.hasOwnProperty("parentId"))

Related

Sort array based off parent ID

I have an array that contains an ID and also a parent_ID. I need to figure out a way to list all objects in the array that share the same parent. The data that generates this array is dynamic and can go up multiple levels deep in some instances.
example array
0: {id: "1", parent_id: "0", name: "Greater New York"...}
1: {id: "2", parent_id: "0", name: "Eastern New York"...}
2: {id: "1001", parent_id: "2", name: "Suffolk"...}
3: {id: "1002", parent_id: "2", name: "Nassau"...}
4: {id: "1003", parent_id: "1", name: "Eastern Long Island"...}
5: {id: "1005", parent_id: "1", name: "Bronx"...}
6: {id: "1006", parent_id: "1", name: "Brooklyn"...}
7: {id: "1007", parent_id: "1", name: "Kings Bay"...}
8: {id: "1008", parent_id: "1", name: "Manhattan"...}
9: {id: "1009", parent_id: "1046", name: "Mid-Hudson"...}
10: {id: "1014", parent_id: "1", name: "Westchester"...}
11: {id: "1015", parent_id: "2", name: "Metro"...}
12: {id: "1016", parent_id: "2", name: "Queens"...}
13: {id: "1017", parent_id: "2", name: "Western Queens"...}
14: {id: "1045", parent_id: "1", name: "Lower Hudson"...}
15: {id: "1046", parent_id: "0", name: "North Hudson"...}
16: {id: "1047", parent_id: "1046", name: "Albany"...}
17: {id: "1048", parent_id: "1046", name: "Berkshire County"...}
18: {id: "1049", parent_id: "1046", name: "Mohawk River"...}
19: {id: "1050", parent_id: "1046", name: "Southern Adirondack"...}
20: {id: "1051", parent_id: "1046", name: "Green Mountain"...}
Right now i have my JSX returning checkboxes in the order that is put out from the array.
{areas.map(area => (
<div className="col-12 mb-2" key={area.id}>
<input data-layout={area.type} type="checkbox" value={area.id}
onChange={props.onChange}/>
<label className="ml-3 mb-0">{area.name}</label>
</div>
))}
what i need to do is match the the parent_id to the id and group them all together,
so all with parent_id: 0 will be top level, then everything will fall under that.
Greater New York
Eastern Long Island
Bronx
Brooklyn
Kings Bay
Manhattan
Westchester
Lower Hudson
Eastern New York
Suffolk
Nassau
Metro
Queens
Western Queens
North Hudson
Mid Hudson
Albany
Berkshire County
Mohawk River
Southern Adarondack
Green Mountain
Any help formulating this logic would be greatly appreciated.
Edit: All i can find to filter is
{areas.filter(area => area.id ===
area.parent_id).map(filteredArea => (
<li>{filteredArea}</li>
))}
I've played with multiple variations of this, including making a separate array for the parent ID's.
If you are trying to group objects by parent_id, below code will be able to help.
let groupBy = (array, key) => {
return array.reduce((result, obj) => {
(result[obj[key]] = result[obj[key]] || []).push(obj);
return result;
}, {});
};
groupBy(data,'parent_id');
Output :
{
'0': [
{ id: '1', parent_id: '0', name: 'Greater New York' },
{ id: '2', parent_id: '0', name: 'Eastern New York' },
{ id: '1046', parent_id: '0', name: 'North Hudson' }
],
'1': [
{ id: '1003', parent_id: '1', name: 'Eastern Long Island' },
{ id: '1005', parent_id: '1', name: 'Bronx' },
{ id: '1006', parent_id: '1', name: 'Brooklyn' },
{ id: '1007', parent_id: '1', name: 'Kings Bay' },
{ id: '1008', parent_id: '1', name: 'Manhattan' },
{ id: '1014', parent_id: '1', name: 'Westchester' },
{ id: '1045', parent_id: '1', name: 'Lower Hudson' }
],
'2': [
{ id: '1001', parent_id: '2', name: 'Suffolk' },
{ id: '1002', parent_id: '2', name: 'Nassau' },
{ id: '1015', parent_id: '2', name: 'Metro' },
{ id: '1016', parent_id: '2', name: 'Queens' },
{ id: '1017', parent_id: '2', name: 'Western Queens' }
],
'1046': [
{ id: '1009', parent_id: '1046', name: 'Mid-Hudson' },
{ id: '1047', parent_id: '1046', name: 'Albany' },
{ id: '1048', parent_id: '1046', name: 'Berkshire County' },
{ id: '1049', parent_id: '1046', name: 'Mohawk River' },
{ id: '1050', parent_id: '1046', name: 'Southern Adirondack' },
{ id: '1051', parent_id: '1046', name: 'Green Mountain' }
]
}
You can then use this list to generate your <li> elements

React-table add total as first row

I'm using react-table 6.9.2. I want to be able to add a row at the top (right under the header) that displays the total of each column.
Here is my function that just outputs a table with static values:
function App() {
const data = [
{
one: 2,
two: 10.4,
three: 10.1,
four: 54,
five: 5,
six: 5,
seven: 10,
eight: 10,
nine: 10
},
{
one: 1,
two: 10.4,
three: 10.1,
four: 54,
five: 5,
six: 5,
seven: 10,
eight: 10,
nine: 10
}
];
return (
<div className="App">
<ReactTable
data={data}
showPagination={false}
columns={[
{
Header: "Sales Overview",
columns: [
{
Header: "one",
id: "one",
accessor: "one",
show: true
},
{
Header: "two",
accessor: "two",
show: true
},
{
Header: "three",
id: "three",
accessor: "three",
show: true
},
{
Header: "four",
id: "four",
accessor: "four",
show: true
},
{
Header: "five",
id: "five",
accessor: "five",
show: true
},
{
Header: "six",
id: "six",
accessor: "six",
show: true
},
{
Header: "seven",
id: "seven",
show: true,
accessor: "seven"
},
{
Header: "eight",
id: "eight",
show: true,
accessor: "eight"
},
{
Header: "nine",
id: "nine",
accessor: "nine",
show: true
}
]
}
]}
loading={false}
minRows={1}
className="-striped -highlight"
/>
</div>
);
}
Is there a way I can add a total row at the top? Even if I get the total value of each column sent within data, can I order it to always display the total row at the top?
In case it's any help, I have also created a sandbox to show the table: https://codesandbox.io/s/2vz3z741op
Thanks in advance!
You can just add a totals entry to the data array:
https://codesandbox.io/s/qv7vjpr69
const getTotals = (data, key) => {
let total = 0;
data.forEach(item => {
total += item[key];
});
return total;
};
function App() {
const data = [
{
one: "first row",
two: 10.4,
...
},
{
one: "second row",
two: 10.4,
...
}
];
data.unshift({
one: "totals",
two: getTotals(data, "two"),
three: getTotals(data, "three"),
four: getTotals(data, "four"),
five: getTotals(data, "five"),
six: getTotals(data, "six"),
seven: getTotals(data, "seven"),
eight: getTotals(data, "eight"),
nine: getTotals(data, "nine")
});

Find items in the array based on the inner array condition

How to find id in an array that is inside of an array of objects
Example:
let arrayobjects = [{
id: 1,
name: "oinoin",
description: ["one", "two", "three"]
}, {
id: 2,
name: "zatata",
description: ["four", "five", "six"]
}];
How can I find the id of the word "two" ?
If you need more than one item, you can filter the array via Array#filter, check if property description for each item contains word two via Array#includes (ES7), then map the result to get only id of those items using Array#map.
let arrayobjects = [
{ id: 1, name: "oinoin", description: ["one", "two", "three"] },
{ id: 2, name: "zatata", description: ["four", "five", "six"] }
];
const ids = arrayobjects.filter(item => item.description.includes('two'))
.map(item => item.id);
console.log(ids);
If you have only one item, you can just use Array#find and do same checking
let arrayobjects = [
{ id: 1, name: "oinoin", description: ["one", "two", "three"] },
{ id: 2, name: "zatata", description: ["four", "five", "six"] }
];
const item = arrayobjects.find(item => item.description.includes('two'));
console.log(item.id);
This snippet might be what you are looking for
arrayobjects.filter( ele => ele.description.includes("two")).map(ele => ele.id)
output :[1]
There may be more efficient way, but i some how find a solution. iterate through the array and match the array item.
var arrayobjects = [{ id: 1, name: "oinoin", description: ["one", "two", "three"]}, { id: 2, name: "zatata", description: ["four", "five", "six"]}];
arrayobjects.forEach(item => {
if(item.description.indexOf('two') != -1 ){
console.log(item.id)
}
})
You can try with indexOf too
arrayobjects.filter(f=>f.description.indexOf('two')>-1)[0].id
let arrayobjects = [
{
id: 1,
name: "oinoin",
description: ["one", "two", "three"]
}, {
id: 2,
name: "zatata",
description: ["four", "five", "six"]
}
];
console.log(arrayobjects.filter(f=>f.description.indexOf('two')>-1)[0].id);
Note
.filter returns an array. So if multiple items are found with two in description then you do not use index [0]. This is just an example of one item in array.
For examples sake, here is a version with old javascript.
var arrayobjects = [
{
id: 1,
name: "oinoin",
description: ["one", "two", "three"]
}, {
id: 2,
name: "zatata",
description: ["four", "five", "six"]
}
];
function findId (desc, arr) {
var idx, arrObjLen = arr.length, results = [];
// Iterate through the first array
for (idx = 0; idx < arrObjLen; idx ++) {
// If the value exists in the 'description' array
if (arr[idx].description.indexOf(desc) > -1) {
// Add it to the results array
results.push(arr[idx].id)
}
}
return results;
}
console.log('Results:', findId('five', arrayobjects));
You could also use Array#reduce if you want to minimise the amount of code you're using:
const arrayobjects = [
{
id: 1,
name: "oinoin",
description: ["one", "two", "three"]
}, {
id: 2,
name: "zatata",
description: ["four", "five", "six"]
}
];
console.log(
arrayobjects.reduce((col, { id, description }) =>
// If description contains the desired value
description.includes('two')
// Add the id to the collector array
? [ ...col, id ] : col, [])
);

How to add values in an array inside an array in AngularJS

I apologize if my title sounds so confusing, as I don't know how to exactly word it. Basically, this is what I'm trying to do.
For example, I have the following array:
var sourceArray = [
{ question: "Question 1", inputType: "radio", answer: "Answer 1", id: "1" },
{ question: "Question 1", inputType: "radio", answer: "Answer 2", id: "2" },
{ question: "Question 1", inputType: "radio", answer: "Answer 3", id: "3" },
{ question: "Question 2", inputType: "radio", answer: "Answer 1", id: "4" },
{ question: "Question 2", inputType: "radio", answer: "Answer 2", id: "5" },
{ question: "Question 2", inputType: "radio", answer: "Answer 3", id: "6" }
]
I want to restructure this so that it'll look like this:
var newArray = [
{
question: "Question 1", inputType: "radio",
choices: [{answer: "Answer 1", id: "1"},
{answer: "Answer 2", id: "2"},
{answer: "Answer 3", id: "3"}
]},
{
question: "Question 2", inputType: "radio",
choices: [{answer: "Answer 1", id: "4"},
{answer: "Answer 2", id: "5"},
{answer: "Answer 3", id: "6"}
]}
]
Answers are grouped by question, so if the next question in the sourceArray is the same with the current, it will push the answers into the choices array.
Is this possible in AngularJS using angular.forEach?
Any help will be appreciated.
Thank you as always for your responses.
Here you go. See the working example below:
// Add a hepler method in the Array to find the value
Array.prototype.find = function(key, value) {
var index = -1;
angular.forEach(this, function(item, i) {
if (item[key] === value) {
index = i;
}
});
return this[index];
};
var app = angular.module("sa", []);
app.controller("FooController", function($scope) {
$scope.sourceArray = [{
question: "Question 1",
inputType: "radio",
answer: "Answer 1",
id: "1"
}, {
question: "Question 1",
inputType: "radio",
answer: "Answer 2",
id: "2"
}, {
question: "Question 1",
inputType: "radio",
answer: "Answer 3",
id: "3"
}, {
question: "Question 2",
inputType: "radio",
answer: "Answer 1",
id: "4"
}, {
question: "Question 2",
inputType: "radio",
answer: "Answer 2",
id: "5"
}, {
question: "Question 2",
inputType: "radio",
answer: "Answer 3",
id: "6"
}];
$scope.newArray = [];
$scope.convert = function() {
// Iterate array
angular.forEach($scope.sourceArray, function(item) {
// Check if the question alrady exists
if (!$scope.newArray.find('question', item.question)) {
// If not, push the question to the array with empty choices
$scope.newArray.push({
question: item.question,
inputType: item.inputType,
choices: []
});
}
var newArrayItem = $scope.newArray.find('question', item.question);
// Push the choices
newArrayItem.choices.push({
answer: item.answer,
id: item.id
});
});
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<div ng-app="sa" ng-controller="FooController">
Before:
<br>{{sourceArray | json}}
<br>
convert
<br>After:
<br>{{newArray | json}}
</div>
You can group together using a for loop,
Here is the code:
function transformArr(orig) {
var newArr = [],
answers = {},
newItem, i, j, cur;
for (i = 0, j = orig.length; i < j; i++) {
cur = orig[i];
if (!(cur.question in answers)) {
answers[cur.question] = {question: cur.question, answers: [],inputType : cur.inputType,id :cur.id};
newArr.push(answers[cur.question]);
}
answers[cur.question].answers.push(cur.answer);
}
return newArr;
}
Working App
You need to filter in the sourceArray, the two Questions List as below:
var question1 = $filter('filter')(sourceArray, {
question: 'Question 1'
});
var question2 = $filter('filter')(sourceArray, {
question: 'Question 2'
});
After that, you should create a new data of array as below:
$scope.questionData = [{
"question": "Question 1",
"inputType": "radio",
"choices": []
}, {
"question": "Question 2",
"inputType": "radio",
"choices": []
}];
Then, you should run loops over the two filtered a variables into the new Array of object:
1):
angular.forEach(question1, function(value, key) {
if (value.question == $scope.questionData[0].question) {
$scope.questionData[0].choices.push({
'answer': value.answer,
'id': value.id
});
}
});
2):
angular.forEach(question2, function(value, key) {
if (value.question == $scope.questionData[1].question) {
$scope.questionData[1].choices.push({
'answer': value.answer,
'id': value.id
});
}
});
Refer here for demo:

Create object using Underscore.js

What is the correct Underscore.js way to create a new object called items that consists of each of the item arrays. Where I could then make a POST of each item.name in one call?
var items = [];
item = [{
name: "item1",
desc: "this is a description of item 1",
qty: 1
},{
name: "item2",
desc: "this is a description of item 2",
qty: 5
},{
name: "item3",
desc: "this is a description of item 3",
qty: 3
}];
items.push(item);
If I understand the question correctly you want to convert an array of items to an object where each key is the name of the object
e.g.
{
item1: {
name: "item1",
desc: "this is a description of item 1",
qty: 1
},
item2: { ... },
item3: { ... },
}
If that's the case then you could use the object function that takes two parameters; the first being the list of property names and the second a list of the values:
var items = [{
name: "item1",
desc: "this is a description of item 1",
qty: 1
},{
name: "item2",
desc: "this is a description of item 2",
qty: 5
},{
name: "item3",
desc: "this is a description of item 3",
qty: 3
}
];
var itemsAsAnObject = _.object( _.pluck(items,'name'), items)

Resources