How to break an functional-style iteration? - javascript

I'm experimenting with functional-style Javascript and have encountered an interesting situation. I have a foreach function that takes a collection and function object:
var Utils = {};
// Applies a functor to each item in a collection.
Utils.foreach = function(collection, functor)
{
for (var i = 0; i < collection.length; i++)
{
functor(collection[i]);
}
};
This is cool. However now I want to implement another function:
// Checks if a collection contains an item.
Utils.has = function(collection, item)
{
Utils.foreach(collection, function(obj) {
if (item === obj) {
return true; // How to force a return from the foreach function?
}
});
return false;
};
As you can see I can't implement the "has" function because my return statement doesn't break the iteration.
Can someone recommend a solution for this problem?

I guess what you want is not actually forEach, but rather some (other languages call it any). The couterpart is every (or all in other languages). You'll find an example implementation on MDC.

You need a modification to each.
Start by modifying has:
Utils.has = function (collection, item) {
var found = false;
Utils.foreach(collection, function (obj) {
if (item === obj) {
found = true;
return false;
}
});
return found;
};
Then you need to modify forEach to end early when it gets false
Utils.foreach = function (collection, functor) {
var prop;
for (prop in collection) {
if (prop.hasOwnProperty(prop)) {
if (functor(collection[prop]) === false) {
return;
}
}
}
};

Here is something real quick and untested ( it is friday 4:50 time to go home). I'll try to test and update this post later. see if this helps:
Utils = {};
Utils.foreach = function(collection, functor) {
loop: for (var i in collection) {
if (functor(collection[i])) {
alert("breaking the loop!");
break loop;
}
}
};
Utils.has = function(collection, item) {
var bolReturn = false;
Utils.foreach(collection, function(obj) {
if (item === obj) {
bolReturn = true;
return true;
}
return false;
});
return bolReturn;
};
Utils.has({"test":""}, "");

I don't think you need to abandon your structure-
why not throw and catch an error to break out of the loop?
Utils.has= function(collection, item){
try{
ControlCenter.foreach(collection, function(obj){
if(item=== obj){
throw 'found it!'
}
});
}
catch(er){
if(er== 'found it!') return true;
}
return false;
};

Related

Mixing Index Array with "Associative Array"

Since I need to access my items sometime by index and sometime by code. Is it a good idea to mix integer index with string index?
Note that the code, index, amount of items never changes after the data is loaded.
I'm thinking of doing something like this, where the same object is pushed and set as a hashtable.
function DataInformation(code, dataValue) {
this.code = code;
this.dataValue = dataValue;
}
var dataList = [];
function fillDataList() {
addNewData(new DataInformation("C1", 111));
addNewData(new DataInformation("C2", 222));
addNewData(new DataInformation("C3", 333));
}
function addNewData(newData) {
dataList.push(newData);
dataList[newData.code] = newData;
}
Then I would be able to access the object with either:
dataList[0].dataValue
dataList["C1"].dataValue
Before I used to loop to find the item.
function findItemByCode(code) {
for (var i = 0; i < dataList.length; i++) {
if (dataList[i].code == code) {
return dataList[i];
}
}
return null;
}
findItemByCode("C1").dataValue
Do you ever need to iterate dataList in strict order? Or is it just a bag of items for which you want random access by a certain key?
If ordered iteration is not a concern, use an object instead of an array. Watch out for key clashes, though.
var dataList = {};
function addNewData(newData) {
dataList[newData.code] = newData;
dataList[newData.dataValue] = newData;
}
// that's it, no other changes necessary
If key clashes can occur - or ordered iteration is necessary, or if you just want to make it particularly clean, use an array and an accompanying index object.
var dataList = [];
var dataIndex = {
byCode: {},
byValue: {}
};
function addNewData(newData) {
dataList.push(newData);
dataIndex.byCode[newData.code] = newData;
dataIndex.byValue[newData.dataValue] = newData;
}
Here is my try using Proxies
// Code goes here
function DataInformation(code, dataValue) {
this.code = code;
this.dataValue = dataValue;
}
var _dataList = [];
var dataList = new Proxy(_dataList, {
get: function(target, name) {
if (target && target.myMap && target.myMap[name]) return target[target.myMap[name]];
return target[name];
},
set: function(obj, prop, value) {
// The default behavior to store the value
obj.myMap = obj.myMap || {};
obj.myMap[value.code] = prop;
obj[prop] = value;
return true;
}
});
function fillDataList() {
addNewData(new DataInformation("C1", 111));
addNewData(new DataInformation("C2", 222));
addNewData(new DataInformation("C3", 333));
}
function addNewData(newData) {
dataList.push(newData);
}
fillDataList();
console.log(dataList[0].dataValue);
console.log(dataList["C1"].dataValue);

undefined while returning a function value in protractor

I have a function which returns a value:
checkValue = function(Name){
var tempIndex=-1;
var nameIndex=0;
return selectElement.all(by.tagName('option')).each(function (element) {
return element.getText().then(function(text){
tempIndex++;
if(text.toString().indexOf(Name)!=-1){
nameIndex=tempIndex;
return nameIndex;
}else{
return nameIndex;
};
});
});
This is called in another function:
checkValue(Name).then(function(value){
logger.info("value ::"+value);
});
When I call the above function the value is displayed as undefined, and in the logs it gets displayed before the checkValue is called.
Any suggestions?
You are getting undefined since this is what each() returns (returns nothing), implementation:
ElementArrayFinder.prototype.each = function(fn) {
return this.map(fn).then(function() {
return null;
});
};
Let's approach it differently, using map():
return selectElement.all(by.tagName('option')).map(function (option, index) {
return {
'text': option.getText(),
'index': index
};
}).then(function (options) {
for (var i = 0; i < options.length; i++) {
if (options[i].text === Name)
{
return options[i].index;
}
}
});
I'm still not sure about the motivation side of the question, why do you need an index of an option in the select. Anyway, this is something you may consider switching to while dealing with select->option constructions:
Select -> option abstraction

Array that can store only one type of object?

Is it possible to create an array that will only allow objects of a certain to be stored in it? Is there a method that adds an element to the array I can override?
Yes you can, just override the push array of the array (let's say all you want to store are numbers than do the following:
var myArr = [];
myArr.push = function(){
for(var arg of arguments) {
if(arg.constructor == Number) Array.prototype.push.call(this, arg);
}
}
Simply change Number to whatever constructor you want to match. Also I would probably add and else statement or something, to throw an error if that's what you want.
UPDATE:
Using Object.observe (currently only available in chrome):
var myArr = [];
Array.observe(myArr, function(changes) {
for(var change of changes) {
if(change.type == "update") {
if(myArr[change.name].constructor !== Number) myArr.splice(change.name, 1);
} else if(change.type == 'splice') {
if(change.addedCount > 0) {
if(myArr[change.index].constructor !== Number) myArr.splice(change.index, 1);
}
}
}
});
Now in ES6 there are proxies which you should be able to do the following:
var myArr = new Proxy([], {
set(obj, prop, value) {
if(value.constructor !== Number) {
obj.splice(prop, 1);
}
//I belive thats it, there's probably more to it, yet because I don't use firefox or IE Technical preview I can't really tell you.
}
});
Not directly. But you can hide the array in a closure and only provide your custom API to access it:
var myArray = (function() {
var array = [];
return {
set: function(index, value) {
/* Check if value is allowed */
array[index] = value;
},
get: function(index) {
return array[index];
}
};
})();
Use it like
myArray.set(123, 'abc');
myArray.get(123); // 'abc' (assuming it was allowed)

Re-Creating Underscore.js _.reject Using _.filter

I am working on a project where I am re-creating many of the fundamental functions included in Underscore.js. I have successfully written the _.filter() function, using my implementation of _.each() (both are below).
Additionally, I have been able to write the _.reject() function using the "easy" way out (simply copy/pasting the _.filter() code and adding the ! in the appropriate place), but for the learning experience, I am looking to develop an alternate implementation that uses actually calls _.filter().
I've seen questions and responses that show how to do this using another Underscore function, _.negate(), but I haven't implemented this function yet in the project, so my question is, is there a way to create _.reject() using a call to the _.filter() function WITHOUT using _.negate()?
_.filter:
_.filter = function(collection, test) {
var results = [];
_.each(collection, function(itemTested) {
if (test(itemTested)) {
results.push(itemTested);
}
});
return results;
};
_.each:
_.each = function(collection, iterator) {
if(Array.isArray(collection)) {
for(var i = 0; i < collection.length; i++) {
iterator(collection[i], i, collection);
}
}
else {
for(var property in collection) {
iterator(collection[property], property, collection);
}
}
};
Current version of _.reject:
_.reject = function(collection, test) {
var results = [];
_.each(collection, function(itemTested) {
if (!test(itemTested)) {
results.push(itemTested);
}
});
return results;
};
Reject function using filter:
var _ = {};
_.reject = function(col, fn) {
return col.filter(function(v) {
return !fn(v);
});
}
// or using your _.filter function
_.reject = function(col, fn) {
return _.filter(col, function(v) {
return !fn(v);
});
}
var odd = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
console.log(odd); // [1,3,5]
JS Bin Example
http://jsbin.com/juyos/1/edit
Well, even if you're not calling _.negate, you still gives you an idea what it would do:
_.reject = function(collection, test) {
return _.filter(collection, function(el, i, collection) {
return !test(el, i, collection);
});
};

JavaScript deferred execution

For a personal challenge, I'm implementing LINQ in JavaScript (well, a set of functions with LINQ-like functionality). However, as of right now, the functions are processing the data immediately; that's correct behavior for some functions (such as Sum or Aggregate), but incorrect for others (such as Select or While).
I'm curious if there's a construct in JavaScript that could get me the same behavior as in .Net, where no real processing happens until the collection is enumerated or a function with immediate execution is used.
Note: I believe this task (implementing LINQ in JS) has already been done. That's not the point. This is a challenge to myself from myself, which is likely to help me increase my understanding of LINQ (and, coincidentally, JS). Beyond personal edification, I'm going to be using LINQ for my job soon, may use JS for my job depending on the needs of individual projects, and I use JS for some things outside of work.
Edit: It seems I've attracted people unfamiliar with LINQ, so I suppose I should give some explanation on that front. LINQ is Language-INtegrated Query, something from .Net. LINQ allows for SQL-like queries on many data sources (including actual SQL relational databases), such as LINQ to Objects, which is what I'm trying to achieve.
One of the features of LINQ is deferred execution on many of the methods. If I have a collection customers and call var query = customers.Where(c => c.Age > 40); (or what it would end up being in JS, var query = customers.Where(function (c) { return c.Age > 40; });), the return value is an interface type, and the actual processing of the collection (returning the subset of the collection containing only customers older than 40) hasn't happened yet. When I use one of the methods without deferred execution (eg, query.First() or query.ToArray()), then all of the deferred processing happens. This could be a chain, such as customers.Where(...).Skip(5).Select(...).OrderBy(...) (each "..." being a function).
The upshot is that code like this:
var collection = [1, 2, 3, 4, 5];
var query = collection.Where(function (n) { return n % 2 == 0; });
collection.push(6);
alert(query.Max());
Would result in "6".
As an addendum, I'm currently implementing this project by prototyping my methods onto both Object and Array, iterating over the elements of this, and skipping any elements which are functions. Something like making an Enumerable class may be superior (and in fact may be required for my deferred execution plan, if something like returning a function or an anonymous object is required), but that's what I've currently got. My functions generally appear as something along these lines:
Object.prototype.Distinct = Array.prototype.Distinct = function (comparer) {
comparer = comparer || function (a, b) { return a == b; };
var result = [];
for (var idx in this) {
var item = this[idx];
if (typeof item == "function") continue;
if (!result.Contains(item, comparer)) result.push(item);
}
return result;
};
Fundamentally what you need to do is return objects from your functions rather than performing operations. The objects you return will contain the code necessary to perform the operations in the future. Consider an example use case:
var myCollection = [];
for(var i = 0; i < 100; i++) { myCollection.push(i); }
var query = Iter(myCollection).Where(function(v) { return v % 2 === 0; })
.Skip(5).Select(function(v) { return v*2; });
var v;
while(v = query.Next()) {
console.log(v);
}
We expect as output:
20
24
28
...
188
192
196
In order to do that we define the methods .Where(), .Skip(), and .Select() to return instances of classes with overridden versions of the .Next() method. Working code that supports this functionality: ( set trace to true to observe that the execution order is lazy)
var trace = false;
function extend(target, src) {
for(var k in src) {
target[k] = src[k];
}
return target;
}
function Iter(wrapThis) {
if(wrapThis.Next) {
return wrapThis;
} else {
return new ArrayIter(wrapThis);
}
}
Iter.prototype = {
constructor: Iter,
Where: function(fn) { return new WhereIter(this, fn); },
Skip: function(count) { return new SkipIter(this, count); },
Select: function(fn) { return new SelectIter(this, fn); }
};
function ArrayIter(arr) {
this.arr = arr.slice();
this.idx = 0;
}
ArrayIter.prototype = extend(Object.create(Iter.prototype),
{
constructor: ArrayIter,
Next: function() {
if(this.idx >= this.arr.length) {
return null;
} else {
return this.arr[this.idx++];
}
}
});
function WhereIter(src, filter) {
this.src = src; this.filter = filter;
}
WhereIter.prototype = extend(Object.create(Iter.prototype), {
constructor: WhereIter,
Next: function() {
var v;
while(true) {
v = this.src.Next();
trace && console.log('Where processing: ' + v);
if(v === null || this.filter.call(this, v)) { break; }
}
return v;
}
});
function SkipIter(src, count) {
this.src = src; this.count = count;
this.skipped = 0;
}
SkipIter.prototype = extend(Object.create(Iter.prototype), {
constructor: SkipIter,
Next: function() {
var v;
while(this.count > this.skipped++) {
v = this.src.Next();
trace && console.log('Skip processing: ' + v);
if(v === null) { return v; }
}
return this.src.Next();
}
});
function SelectIter(src, fn) {
this.src = src; this.fn = fn;
}
SelectIter.prototype = extend(Object.create(Iter.prototype), {
constructor: SelectIter,
Next: function() {
var v = this.src.Next();
trace && console.log('Select processing: ' + v);
if(v === null) { return null; }
return this.fn.call(this, v);
}
});
var myCollection = [];
for(var i = 0; i < 100; i++) {
myCollection.push(i);
}
var query = Iter(myCollection).Where(function(v) { return v % 2 === 0; })
.Skip(5).Select(function(v) { return v*2; });
var v;
while(v = query.Next()) {
console.log(v);
}
You also may want to look into "string lambdas" to make your queries much more readable. That would allow you to say "v*2" instead of function(v) { return v*2; }
I am not entirely clear on what exactly you wish to do, but I think what you should look into is the defineProperty method. What you would probably wish to do is then to redefine the .length property and execute the code only once it's read. Or if you want to do it only once the property itself is read do it at that point. Not sure how LINQ works or even what it is, so that's why I am a bit vague. Either way, with defineProperty you can do something like
Object.defineProperty(o, "a", { get : function(){return 1;});
Allowing you to do actions only once the property is accessed (and you can do a lot more than that as well).

Categories