How to create a unique array which has objects as elements? - javascript

I have an array of students and I want to create an unique array of this students. Each student has a unique id value and I want to compare with this id value.
Here is a Student object;
{
"id" = "3232aab1",
//some other properties
}

var Students =[
{
"id" : "3232aab1" //some other properties
} ,
{
"id" : "3232aab1" //some other properties
},
{
"id" : "3232aab2" //some other properties
} ,
{
"id" : "3232aab3" //some other properties
} ,
{
"id" : "3232aab2" //some other properties
} ];
var tmpObj = {};
var uniqArray = Students.reduce(function(acc,curr){
if (!tmpObj[curr.id]){
tmpObj[curr.id] = true;
acc.push(curr)
}
return acc;
},[]);
console.log(uniqArray);

var a=[];
a.push({id:1,name:"something"});
// repeat similar;
To access an id
a[index].id;
Sample code to search
var elem = 1; // id to be searched
//loop
for(var i=0; i<a.length; i++){
if(elem == a[i].id){
break;
}
}
// now a[i] will return the required data {id:1,name:"something"}
// a[i].id = > 1 and a[i].name => something

I'd probably take an approach similar to this...
class Students extends Map {
set(key, value) {
if (this.has(key)) { throw new Error('Student already there'); }
return super.set(key, value);
}
}
const students = new Students();
students.set(1, { name: 'Peter' });
console.log(students.get(1));
// students.set(1, { name: 'Gregor' }); this throws

If you have underscore, you can use the following
ES6
_.uniq(Students, student=>student.id)
ES5
_.uniq(Students, function(student){return student.id;})

Related

Find in object to Edit or Add

I have an object productCounts
[{provisioned=2.0, product=str1, totalID=1.0},
{product=str2, provisioned=4.0, totalID=3.0},
{provisioned=6.0, product=str3, totalID=5.0}]
I have an array uniqueProduct
[str1, str2, str3, str4]
I am then looping a dataset to get the totalID count, add it to the product's totalID but if it doesn't exist, push it to the object.
var countID = 0;
uniqueProduct.forEach(
currentproduct => {
countID = 0;
for (var i = 0; i < shtRng.length; ++i) {
if (shtRng[i][ProductCol].toString() == currentproduct) { // && shtRng[i][IDcol].toString().length>4){
countID++;
}
}
if (countID == 0) {
return;
}
console.log(currentproduct + ": " + countID);
}
)
This works perfectly to return the countID per product in uniqueProduct
Rather than logging the result, I would like to add it to the object like this... If the current unique product is not in the productCounts object, add it.
let obj = productCounts.find((o, i) => {
if (o.product == currentproduct) {
productCounts[i] = { product: currentproduct, totalID: productCounts[i].totalID+countID, provisioned: productCounts[i].provisioned };
return true;
} else {
productCounts.push({ product: currentproduct, totalID: countID, provisioned: 0 });
return true;
}
});
In my head, this should work but it appears to skip some records or add the product multiple times. How do I add to the object correctly?
Expected output is the object to be something similar to:
[{provisioned=2.0, product=str1, totalID=35.0},
{product=str2, provisioned=4.0, totalID=8.0},
{provisioned=6.0, product=str3, totalID=51.0},
{provisioned=6.0, product=str4, totalID=14.0}]
The argument to find() is a function that returns a boolean when the element matches the criteria. The if statement should use the result of this, it shouldn't be in the condition function.
let obj = productCounts.find(o => o.product == currentProduct);
if (obj) {
obj.totalId += countID;
} else {
productCounts.push(productCounts.push({ product: currentproduct, totalID: countID, provisioned: 0 });
}
BTW, your life would be easier if you used an object whose keys are the product names, rather than an array of objects. You can easily turn the array of objects into such an object:
let productCountsObj = Object.fromEntries(productCounts.map(o => [o.product, o]));
if (currentProduct in productCountsObj) {
productCountsObj[currentProduct].totalID += countID;
} else {
productCountsObj[currentProduct] = { product: currentproduct, totalID: countID, provisioned: 0 };
}

AngularJs - check if value exists in array object

var SelectedOptionId = 957;
$scope.array = [{"957":"1269"},{"958":"1265"},{"956":"1259"},{"957":"1269"},{"947":"1267"}]
Is there a way of checking if a value exists in an that kind of array objects. I am using Angular and underscore.
I have tried all this -
if ($scope.array.indexOf(SelectedOptionId) === -1) {console.log('already exists')}
and
console.log($scope.array.hasOwnProperty(SelectedOptionId)); //returns false
and
console.log(_.has($scope.array, SelectedOptionId)); //returns false
You could use Array#some and check with in operator.
exists = $scope.array.some(function (o) {
return SelectedOptionId in o;
});
Check this
function checkExists (type) {
return $scope.array.some(function (obj) {
return obj === type;
}
}
var chkval=checkExists("your value")
Try this:
if($scope.array[SelectedOptionId] || _.includes(_.values($scope.array, SelectedOptionId))) { }
That should cover both a key and a value.
let selectedOptionId = "957";
let array = [{"957":"1269"},{"958":"1265"},{"956":"1259"},{"957":"1269"},{"947":"1267"}];
let filtered = array.filter(function(element){
return Object.keys(element)[0] === selectedOptionId;
});
console.log(filtered);
console.log(_.some($scope.array, function(o) { return _.has(o, "957"); }));
using underscore
You can use filter for this. The following code should return you output array with matching results, if it exists, otherwise it will return an empty array :
var array = [{"957":"1269"},{"958":"1265"},{"956":"1259"},{"957":"1269"},{"947":"1267"}];
var SelectedOptionId = 957;
var result = array.filter(
function(item) {return item[SelectedOptionId]}
)
console.log(result);
For your input it returns:
[ { '957': '1269' }, { '957': '1269' } ]
You can do it using the in operator or the hasOwnProperty function, to check for the existence of a key in an object inside the given array.
The way you've tried using hasOwnProperty function didn't work because you were checking it directly on the array instead of checking against the items in the array.
Check the below code snippet.
angular
.module('demo', [])
.controller('HomeController', DefaultController);
function DefaultController() {
var vm = this;
vm.items = [{
"957": "1269"
}, {
"958": "1265"
}, {
"956": "1259"
}, {
"957": "1269"
}, {
"947": "1267"
}];
var key = '957';
var isExists = keyExists(key, vm.items);
console.log('is ' + key + ' exists: ' + isExists);
function keyExists(key, items) {
for (var i = 0; i < items.length; i++) {
// if (key in items[i]) {
if (items[i].hasOwnProperty(key)) {
return true;
}
}
return false;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demo">
<div ng-controller="HomeController as home">
{{home.items | json}}
</div>
</div>
Different ways to do this :
Using Object hasOwnProperty() method.
Working demo :
var SelectedOptionId = 957;
var arrayObj = [{"957":"1269"},{"958":"1265"},{"956":"1259"},{"957":"1269"},{"947":"1267"}];
function checkOption(key) {
for(var i in arrayObj) {
if(arrayObj[i].hasOwnProperty(key) == true) {
return key+" exists.";
} else {
return key+" Not exists.";
}
}
};
console.log(checkOption(SelectedOptionId)); // 957 exists.
using Array filter() method.
Working demo :
var SelectedOptionId = 957;
var arrayObj = [{"957":"1269"},{"958":"1265"},{"956":"1259"},{"957":"1269"},{"947":"1267"}];
var result = arrayObj.filter(function(elem) {
return elem[SelectedOptionId]
});
if(result == '') {
console.log(SelectedOptionId+" not exists.");
} else {
console.log(SelectedOptionId+" exists.");
}
using Array some() method as suggested by Nina Scholz.
Working demo :
var SelectedOptionId = 957;
var arrayObj = [{"957":"1269"},{"958":"1265"},{"956":"1259"},{"957":"1269"},{"947":"1267"}];
var result = arrayObj.some(function (o) {
return SelectedOptionId in o;
});
if(result == '') {
console.log(SelectedOptionId+" not exists.");
} else {
console.log(SelectedOptionId+" exists.");
}

How to use unique filter in controller in AngularJS

I would like to filter an array by unique category in controller and then use the filtered array with ng-repeat in html page. My array is:
$scope.tabs = [
{OBJECTID:1, TYPES:8, Category:"Pharmacies",Name_EN:"antonis" , text : "Home"},
{OBJECTID:2, TYPES:8, Category:"Opticians",Name_EN:"antonis" , text : "Games"},
{OBJECTID:3, TYPES:8, Category:"Doctors", Name_EN:"antonis" , text : "Mail"},
{OBJECTID:4, TYPES:8, Category:"Clinics", Name_EN:"antonis" , text : "Car"},
{OBJECTID:5, TYPES:8, Category:"Clinics", Name_EN:"antonis" , text : "Profile"},
{OBJECTID:6, TYPES:8, Category:"Clinics", Name_EN:"antonis" , text : "Favourites"},
{OBJECTID:7, TYPES:8, Category:"Pharmacies",Name_EN:"antonis" , text : "Chats"},
{OBJECTID:8, TYPES:4, Category:"Sights",Name_EN:"antonis" , text : "Settings"},
{OBJECTID:9, TYPES:4, Category:"Meuseums",Name_EN:"antonis" ,text : "Home"},
{OBJECTID:10, TYPES:4, Category:"Meuseums",Name_EN:"antonis1" , text : "Home"}
];
the filtered array will be like this:
$scope.FilteredArray = [
{Category:"Pharmacies"},
{Category:"Opticians"},
{Category:"Doctors"},
{Category:"Clinics"},
{Category:"Sights"},
{Category:"Meuseums"},
];
Thanks in advance.
Use unique filter inside controller and apply ng-repeat on filtered array
//Filtered array
$scope.filteredArray = $filter('unique')($scope.tabs,'Category');
<ul>
<li ng-repeat="tab in filteredArray">{{tab.Category}}</li>
</ul>
Filter
angular.module('myapp').filter('unique', function () {
return function (items, filterOn) {
if (filterOn === false) {
return items;
}
if ((filterOn || angular.isUndefined(filterOn)) && angular.isArray(items)) {
var hashCheck = {}, newItems = [];
var extractValueToCompare = function (item) {
if (angular.isObject(item) && angular.isString(filterOn)) {
return item[filterOn];
} else {
return item;
}
};
angular.forEach(items, function (item) {
var valueToCheck, isDuplicate = false;
for (var i = 0; i < newItems.length; i++) {
if (angular.equals(extractValueToCompare(newItems[i]), extractValueToCompare(item))) {
isDuplicate = true;
break;
}
}
if (!isDuplicate) {
newItems.push(item);
}
});
items = newItems;
}
return items;
};
});
FULL EXAMPLE
You can also do it without angular filter. If you have used lodash module in your angular application then you can simply do it with below lodash function. It will return uniq records by whatever key you want.
_.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
// => [{ 'x': 1 }, { 'x': 2 }]
You can do this too,
$scope.unique = {};
$scope.distinct = [];
for (var i in $scope.tabs) {
if (typeof($scope.unique[$scope.tabs[i].Category]) == "undefined") {
$scope.distinct.push($scope.tabs[i].Category);
}
$scope.unique[$scope.tabs[i].Category] = 0;
}
DEMO
That code could be used to create a method this will give you an array of strings also you can modify to create object array -
var flags = [], $scope.FilteredArray= [], l = $scope.tabs.length, i;
for( i=0; i<l; i++) {
if( flags[$scope.tabs[i].Category]) continue;
flags[$scope.tabs[i].Category] = true;
$scope.FilteredArray.push($scope.tabs[i].Category);
}
Use the default unique filter:
<select ng-model="tab" ng-repeat="uni in tabs | unique:'Category'">
</select>

How to declare array of specific type in javascript

Is it possible in java script to explicitly declare array to be an array of int(or any other type)?
something like var arr: Array(int) would be nice...
var StronglyTypedArray=function(){
this.values=[];
this.push=function(value){
if(value===0||parseInt(value)>0) this.values.push(value);
else return;//throw exception
};
this.get=function(index){
return this.values[index]
}
}
EDITS: use this as follows
var numbers=new StronglyTypedArray();
numbers.push(0);
numbers.push(2);
numbers.push(4);
numbers.push(6);
numbers.push(8);
alert(numbers.get(3)); //alerts 6
Array of specific type in typescript
export class RegisterFormComponent
{
genders = new Array<GenderType>();
loadGenders()
{
this.genders.push({name: "Male",isoCode: 1});
this.genders.push({name: "FeMale",isoCode: 2});
}
}
type GenderType = { name: string, isoCode: number }; // Specified format
If simply you want to restrict user to push values as per first value entered you can use below code
var stronglyTypedArray = function(type) {
this.values = [];
this.typeofValue;
this.push = function(value) {
if(this.values.length === 0) {
this.typeofValue = typeof value;
this.pushValue(value);
return;
}
if(this.typeofValue === typeof value) {
this.pushValue(value);
} else {
alert(`type of value should be ${this.typeofValue}`)
}
}
this.pushValue = function(value) {
this.values.push(value);
}
}
If you want to pass your own type, you can customize the above code a bit to this
var stronglyTypedArray = function(type) {
this.values = [];
this.push = function(value) {
if(type === typeof value) {
this.pushValue(value);
} else {
alert(`type of value should be ${type}`)
}
}
this.pushValue = function(value) {
this.values.push(value);
}
}

Find an element in an array recursively

I have an array of objects. Every object in the array has an id and an item property that is an array containing other object. I need to be able to find an element in an array by id. Here is a sample of what I have done so far, but the recursive function is always returning undefined.
How can I quit the function and return the item when I have called the function recursively several times?
$(function () {
var treeDataSource = [{
id: 1,
Name: "Test1",
items: [{
id: 2,
Name: "Test2",
items: [{
id: 3,
Name: "Test3"
}]
}]
}];
var getSubMenuItem = function (subMenuItems, id) {
if (subMenuItems && subMenuItems.length > 0) {
for (var i = 0; i < subMenuItems.length; i++) {
var item;
if (subMenuItems[i].Id == id) {
item = subMenuItems[i];
return item;
};
getSubMenuItem(subMenuItems[i].items, id);
};
};
};
var searchedItem = getSubMenuItem(treeDataSource, 3);
alert(searchedItem.id);
});
jsFiddle
You should replace
getSubMenuItem(subMenuItems[i].items, id);
with
var found = getSubMenuItem(subMenuItems[i].items, id);
if (found) return found;
in order to return the element when it is found.
And be careful with the name of the properties, javascript is case sensitive, so you must also replace
if (subMenuItems[i].Id == id) {
with
if (subMenuItems[i].id == id) {
Demonstration
Final (cleaned) code :
var getSubMenuItem = function (subMenuItems, id) {
if (subMenuItems) {
for (var i = 0; i < subMenuItems.length; i++) {
if (subMenuItems[i].id == id) {
return subMenuItems[i];
}
var found = getSubMenuItem(subMenuItems[i].items, id);
if (found) return found;
}
}
};
I know its late but here is a more generic approach
Array.prototype.findRecursive = function(predicate, childrenPropertyName){
if(!childrenPropertyName){
throw "findRecursive requires parameter `childrenPropertyName`";
}
let array = [];
array = this;
let initialFind = array.find(predicate);
let elementsWithChildren = array.filter(x=>x[childrenPropertyName]);
if(initialFind){
return initialFind;
}else if(elementsWithChildren.length){
let childElements = [];
elementsWithChildren.forEach(x=>{
childElements.push(...x[childrenPropertyName]);
});
return childElements.findRecursive(predicate, childrenPropertyName);
}else{
return undefined;
}
}
to use it:
var array = [<lets say an array of students who has their own students>];
var joe = array.findRecursive(x=>x.Name=="Joe", "students");
and if you want filter instead of find
Array.prototype.filterRecursive = function(predicate, childProperty){
let filterResults = [];
let filterAndPushResults = (arrayToFilter)=>{
let elementsWithChildren = arrayToFilter.filter(x=>x[childProperty]);
let filtered = arrayToFilter.filter(predicate);
filterResults.push(...filtered);
if(elementsWithChildren.length){
let childElements = [];
elementsWithChildren.forEach(x=>{
childElements.push(...x[childProperty]);
});
filterAndPushResults(childElements);
}
};
filterAndPushResults(this);
return filterResults;
}

Categories