countBy Method into a Function using Javascript - javascript

I'm trying to write a countBy function, identical to the countBy method in Javascript. Here is what I have so far:
var array = [1,2,4,4,5];
function countBy(collection, func) {
var object = {} ;
for (var i=0;i<=0; i++) {
for (var key in object) {
if (func(collection[i]) === object.key) {
object.key ++;
} else {
object.key = 1;
}
}
}
return object
}
alert(countBy(array, function(n) {return Math.floor(n);}));
What the code intends to do is search through the collection array to see if a value there matches a key in object. If it has found a match in the collection array, increment that key value by one. If it has not found one, create a new key value. Therefore, the result that should be alerted is: {4:2, 1:1, 2:1, 5:1}. But it seems like my output is [object Object]. What am I doing wrong??

for (var i=0;i<=0; i++) {
This will run exactly once instead of iterating through the collection.
for (var key in object) {
if (func(collection[i]) === object.key) {
This does the wrong thing; you should call func only once in each iteration and then look up the result of the function call in your object.
object.key ++;
This doesn't do what you want; it's better to use the array dereference operator instead.
function countBy(collection, func)
{
var object = Object.create(null);
collection.forEach(function(item) {
var key = func(item);
if (key in object) {
++object[key];
} else {
object[key] = 1;
}
});
return object;
}

Related

Recursive javascript function that converts nested object keys to string and store all keys in arrray

I am trying to write a javascript recursive function that receives one parameter - nested JSON object.
The function goes through the potentially infinitely nested object and converts all the keys (property names) to a string that is stored in array. Array is returned to a place where the function was called.
Example of JSON object:
{
OBJECT1: {
ATTRIBUTE3: {
PARAMETER2: {
PROPERTY1: {
}
}
}
}
}
The object does not hold any values.
What i tried and did not work:
function convertKeysToString(obj) {
let keys = [];
for (let key in obj) {
if (typeof obj[key] === 'object') {
keys = keys.concat(convertKeysToString(obj[key]));
} else {
keys.push(key.toString());
}
}
return keys;
}
As a result, I expected that returned key is pushed to an array, but the funciton didnt get the key at all or was not pushed to keys array.
Another code I tried:
function getNestedObjectKeys(obj) {
var keys = []
var firstLevel = null
var property = Object.keys(obj)
property = property[0]
firstLevel = Object.keys(obj[property])[0]
if (firstLevel == undefined) {
return 0
}
let returnedValue = keys.unshift(getNestedObjectKeys(obj[property]))
if (returnedValue == 0) {
return Object.keys(obj[property])[0]
}
returnedValue = Object.keys(obj[property])[0]
if (returnedValue != obj[property[0]]) {
return Object.keys(obj[property])[0]
}
else if (returnedValue == firstLevel) {
return keys
}
}
The function should return the key name and push (unshift) it to string and then return it, but the unshift doesnt do what I expect and in the returnedValue is not a expected returned string.
I approached it the way that the function findd the deepest (empty) object, and starts returning the name of the key. The thing is that I must return the key name AND push it to the string, which I can't find the way to accomplish at once.
Your first solution is pretty close, but has one problem (well, one main problem): when the value is type object, you don't add its key to the array. So how is it supposed to get into the array? Give this a shot:
function convertKeysToString(obj) {
let keys = [];
for (let key in obj) {
keys.push(key.toString());
if (typeof obj[key] === 'object') {
keys = keys.concat(convertKeysToString(obj[key]));
}
}
return keys;
}
Other things you may want to consider:
typeof null is object.
typeof [] is also object.
You could have a look to object, which are truthy and typeof object.
const
getKeys = object => (keys => [
...keys.flatMap(key => object[key] && typeof object[key] === 'object'
? [key, ...getKeys(object[key])]
: [key]
)
])(Object.keys(object)),
data = { OBJECT1: { ATTRIBUTE3: { PARAMETER2: { PROPERTY1: {} } } } },
result = getKeys(data);
console.log(result);

How to easily get the current iteration property of a Javascript for loop?

Let's say I have the following code:
for(var k in objectWithVeryLongName){
objectWithVeryLongName[k].something();
objectWithVeryLongName[k].otherSomething();
objectWithVeryLongName[k].thirdSomething();
...
objectWithVeryLongName[k].nthSomething();
}
Is there a way to get the current property of the object without having to store it in a variable like that:
var prop;
for(var k in objectWithVeryLongName){
prop = objectWithVeryLongName[k];
prop.something();
prop.otherSomething();
...
prop.nthSomething();
}
The first piece of code is disturbing to look at, while the second one needlessly uses more memory. Is there a way to avoid both problems at once?
Just use of instead of in?
For instance:
for(var i of [1,5,3,4]) {
console.log(i)
}
Returns:
1
5
3
4
EDIT 1:
May be duplicate of this: For-each over an array in JavaScript?
EDIT 2:
Here is an example using JSON objects:
var arr = [];
for (var i = 0; i < 5; i++) {
arr.push({
id : i,
func : function () {
alert("hello world\nfrom " + this.id);
}
});
}
for (var i of arr) {
console.log(i.id);
i.func();
}
EDIT 3:
You can't apply of directly to objects because of the way objects and arrays work.
An array is a list of individual, unrelated values that knows nothing of eachother or the array that holds them. There is no "this" as each are their own independent variable.
An object however is not a set of references to independent variables but a scope for a set of functions and variables that are contained WITHIN the object.
Therefore you can't logically use of because that would reference the individual keys as standalone variables, even though they only live within the object.
However you could polyfill a solution for this using something like this:
var master = {};
for (var i = 0; i < 10; i++) {
master[i] = {
id : Math.round(Math.random() * 1000),
func : function () {
alert("hello world\nfrom " + this.id);
}
}
}
//Polyfill to get elements based upon the IN loop
Object.prototype.getValues = function (obj) {
if (typeof obj === "undefined") {
obj = this;
}
var values = [];
for (var i in obj) {
if (i != 'getValues') {
values.push(obj[i]);
}
}
return values;
}
//Loop through the values delivered by the polyfill
for (var a of master.getValues()) {
console.log(a);
}
This method gives a standard method on all objects to generate a reference to each of their inner properties and then we simply return the array.
That array then contains individual references to each underlying property, allowing you to loop over them in an of loop.
By the way, the code above should return a list of objects in the console looking like this:
Object { id=723, func=function(), getValues=function()}
Object { id=857, func=function(), getValues=function()}
Object { id=8, func=function(), getValues=function()}
Object { id=160, func=function(), getValues=function()}
Object { id=573, func=function(), getValues=function()}
Object { id=959, func=function(), getValues=function()}
Object { id=512, func=function(), getValues=function()}
Object { id=532, func=function(), getValues=function()}
Object { id=840, func=function(), getValues=function()}
Object { id=72, func=function(), getValues=function()}
From here you could just do:
for (var a of master.getValues()) {
a.func();
}
To access the object properties.

Javascript check for existing object in Array

I have some simple objects in an Array. I want to add new objects to the Array only if they are not already in it, based on an object property.
var o = {text: 'foo'}
var a = [o]
var checkExisting = function (list, obj) {
list.forEach(function(elem) {
if (elem.text === obj) {
return true
}
}
}
checkExisting(a, 'foo')
This doesn't work. I can't figure out why. Any help or alternatives would be great.
Because you can't return value from callback in forEach, you can use for, like this
var checkExisting = function (list, obj) {
for (var i = 0, len = list.length; i < len; i++) {
if (list[i].text === obj) {
return true;
}
}
}
This can be done very similar to how you are but with .every() because .forEach() always returns undefined. So you can't chain it either.
.every() runs a method over every element like .forEach() but if it receives a false value it will abort. Finally if every iteration returns true it will return true to the caller otherwise it will return false.
Because we return false to make it abort when a value is found (so it wont keep iterating), we then have to flip the value it returns before we return it from checkExisting.
So using that you could do something like:
var checkExisting = function (list, obj) {
return !list.every(function(elem) {
return elem.text !== obj;
});
}
Obviously you would have to extend that for error handling if the object doesn't have a property text etc.
See fiddle: http://jsfiddle.net/reLsqhkm/
And docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every

How to make JavaScript objects and arrays behave the same way?

I wanted to write one version of a function that iterated over both Array objects and Objects, with minimal duplicate code. Something like:
function (arr_or_obj) {
arr_or_obj.forEach( function(key,value) {
// do stuff with key and value
});
}
This was before I realized that (in Chrome at least), Object.keys returns a list of the keys for an array. So I could use that to treat the Array like an object. Like so:
function (arr_or_obj) {
var keys = Object.keys(arr_or_obj);
keys.forEach( function(key) {
var value = arr_or_obj[key];
// do stuff with key and value
});
}
Problem solved. But this was not before I wrote my own "JavaScript pseudo-Array iterator". The only advantage of this was that instead of getting a list of keys for the Array (which could be very long), we save memory by producing only the return values we need. Like so:
function create_iterator(max) {
var jkeys = {};
jkeys.count_ = 0;
jkeys.length = max;
jkeys.getter_ = function() {
var returnable = jkeys.count_;
jkeys.count_ += 1;
jkeys.__defineGetter__(jkeys.count_,jkeys.getter_);
delete jkeys[jkeys.count_-1];
return returnable;
};
jkeys.__defineGetter__(0, jkeys.getter_);
return jkeys;
}
Which you can then call by going:
var z = create_iterator(100);
z[0];
>> 0
z[0];
>> undefined
z[1];
>> 1;
z[2]
>> 2;
...
This is sort of a question and answer in one, but the obvious question is, is there a better way to do this without using Object.keys?
Object.keys gives you an array of the object's own enumerable properties. That is, properties it has itself, not from its prototype, and that are enumerable (so not including things like length on arrays, which is a non-enumerable property).
You can do the same thing with for-in if you use correct safeguards:
var key;
for (key in arr_or_obj) {
if (arr_or_obj.hasOwnProperty(key)) {
// do something with it
}
}
Now you're doing the same thing you were doing with Object.keys.
But, note that this (and Object.keys) will include properties people put on arrays that aren't array indexes (something which is perfectly valid in JavaScript). E.g.:
var key;
var a = [1, 2, 3];
a.foo = "bar";
for (key in a) {
if (a.hasOwnProperty(key)) {
console.log(key); // Will show "foo" as well as "0", "1", and "2"
}
}
If you want to only process array indexes and not other properties, you'll need to know whether the thing is an array, and then if so use the "is this an index" test:
var key;
var isArray = Array.isArray(arr_or_obj);
// Or (see below):
//var isArray = Object.prototype.toString.call(arr_or_obj) === "[object Array]";
for (key in arr_or_obj) {
if (a.hasOwnProperty(key) &&
(!isArray || isArrayIndex(key))
) {
console.log(key); // Will only show "0", "1", and "2" for `a` above
}
}
...where Array.isArray is a new feature of ES5 which is easily shimmed for older browsers if necessary:
if (!Array.isArray) {
Array.isArray = (function() {
var toString = Object.prototype.toString;
function isArray(arg) {
return toString.call(arg) === "[object Array]";
}
return isArray;
})();
}
...and isArrayIndex is:
function isArrayIndex(key) {
return /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294; // 2^32 - 2
}
See this other answer for details on that (where the magic numbers come from, etc.).
That loop above will loop through an object's own enumerable properties (all of them) if it's not an array, and loop through the indexes (but not other properties) if it's an array.
Taking it a step further, what if you want to include the properties the object gets from its prototype? Object.keys omits those (by design). If you want to include them, just don't use hasOwnProperty in the for-in loop.
You can try something like this...
Live Demo
function forIn(obj) {
var isArray = Array.isArray(obj),
temp = isArray ? obj : Object.keys(obj);
temp.forEach(function (value, index, array) {
console.log(this[isArray ? index : value]);
}, obj);
}
You can write:
for (key in arr_or_obj) {
if (arr_or_obj.hasOwnProperty(key) {
value = arr_or_obj[key];
// do stuff with key and value
}
}

Check if value exists in JavaScript object

How would I check in my array of objects, if a specific item exists (in my case MachineId with id 2)?
[{"MachineID":"1","SiteID":"20"},{"MachineID":"2","SiteID":"20"},{"MachineID":"3","SiteID":"20"},{"MachineID":"4","SiteID":"20"}]
I tried this:
if (index instanceof machineIds.MachineID) {
alert('value is Array!');
} else {
alert('Not an array');
}
In cross browser way you may use jQuery.grep() method for it:
var item = $.grep(machineIds, function(item) {
return item.MachineID == index;
});
if (item.length) {
alert("value is Array!");
}
The simplest to understand solution is to loop over the array, and check each one.
var match;
for (var i = 0; i < yourArray.length; i++) {
if (yourArray[i].MachineId == 2)
match = yourArray[i];
}
Note if there is more than one matching item, this will return the last one. You can also dress this up in a function.
function findByMachineId(ary, value) {
var match;
for (var i = 0; i < ary.length; i++) {
if (ary[i].MachineId == value)
match = ary[i];
}
return match;
}
There are many standard solution, you don't need third party libraries or loop iteratively.
Array some method - since JavaScript 1.6.
Array find method - since ES6
Array findIndex method - since ES6
For example, using some();
var yourArray = [{"MachineID":"1","SiteID":"20"},{"MachineID":"2","SiteID":"20"},{"MachineID":"3","SiteID":"20"},{"MachineID":"4","SiteID":"20"}];
var params = {searchedID: "2", elementFound: null};
var isCorrectMachineID = function(element) {
if (element.MachineID == this.searchedID);
return (this.elementFound = element);
return false;
};
var isFound = yourArray.some(isCorrectMachineID, params)
Array some method accepts two parameters:
callback - Function to test for each element.
thisObject - Object to use as this when executing callback.
Callback function is not coupled with the iteration code and, using thisObject parameter, you can even return to the caller the element found or more data.
If such an element is found, some immediately returns true
http://jsfiddle.net/gu8Wq/1/
You could use this condition:
if (arr.filter(function(v){return this.MachineID == 2;}).length > 0)
Old question at this point, but here's an ES6 solution that uses Array.find:
let machine2 = machines.find((machine) => machine.id === '2');
if (machine2) {
// ...
}
var item = [{"MachineID":"1","SiteID":"20"},{"MachineID":"2","SiteID":"20"},{"MachineID":"3","SiteID":"20"},{"MachineID":"4","SiteID":"20"}];
var newItem = item.filter(function(i) {
return i.MachineID == 2; //it will return an object where MachineID matches with 2
});
console.log(newItem); // will print [{"MachineID":"2","SiteID":"20"}]

Categories