Set of pairs of numbers in Javascript - javascript

ES6 has a new Set data structure for storing sets of unique objects. However it is based on object references as opposed to value comparisons. As far as I can tell this makes it impossible to have a set of pairs of numbers without stringifying.
For example, typing in Chrome's console (needs Chrome 38+):
> var s = new Set();
< undefined
> s.add([2, 3]);
< Set {[2, 3]}
> s.has([2, 3])
< false <--- was hoping for 'true'
This appears to be by design: since I passed a different array of [2, 3] to has(), it returns false, because although the contents is the same it only looks at object references, and I allocated a new and different array to pass to has(). I would need to store a reference to the original array I passed to add() to check with has(), but this is not always possible. For example if the number pairs represent co-ordinates, I might need to check if the set has [obj.x, obj.y], but this will always return false since it allocates a new array.
The workaround is to stringify the arrays and key on strings like "2, 3" instead. However in something performance-sensitive like a game engine, it is unfortunate if every set access needs to make a string allocation and convert and concatenate number strings.
Does ES6 provide any feature to solve this problem without stringifying, or is there any feature on the horizon with ES7 that could help as well?

It is not perfectly optimal for very compute-intensive tasks, but you could use a concatenated string using template literals for a more idiomatic approach that still maintains efficiency, e.g.
set.add(`${x}_${y}`);
and retrieval:
set.get(`${i}_${j}`);
(note I've purposely avoided use of , as a delimeter since it can be confusing in some fields such as finance).
Another thing that could be done is grabbing the width of the first dimension to flatten an array if you know the bounds e.g.
set.get(x+y*width);
or if you're working with small numbers in general (not exceeding 10,000s) and don't know what the max width would be, you could use an arbitrary very large number. This is slightly less optimal but still better than string concat:
set.get(x+y*Math.floor(Math.sqrt(Number.MAX_SAFE_INTEGER)));
Again, these are not perfect solutions since they do not work with very large numbers where x*y may exceed Number.MAX_SAFE_INTEGER, but they are some things in your toolbox without needing to know a fixed array size.
[Super late here, but since ES7 had not fixed things after all and I noticed this was not specifically mentioned if others are weighing the pros/cons, two approaches (the first explicitly does not solve, the second may possibly)]

As you've noted [2, 3] === [2, 3] is false, meaning you can't use Set like this; however, is Set really the best option for you?
You may find that using a two-level data structure like this will be better for you
var o = {};
function add(o, x, y) {
if (!o[x]) o[x] = {};
o[x][y] = true;
}
function has(o, x, y) {
return !!(o[x] && o[x][y]);
}
function del(o, x, y) {
if (!o[x]) return;
delete o[x][y];
// maybe delete `o[x]` if keys.length === 0
}
You could do a similar structure with a Map pointing to Sets if you wanted to use ES6

is there any feature on the horizon with ES7 that could help as well?
There is a proposal in ECMAScript 7 to add Value Objects. Basically, it's a new immutable data type where identical value objects are compared by value, not by reference.
Depending on what kinds of value objects are implemented and/or if custom ones can be defined, they may solve this issue.

Related

Is there a way to return the rest of a JavaScript array

Is there a way to return the rest of an array in JavaScript i.e the portion of the array that consists of all elements but the first element of the array?
Note: I do not ask for returning a new array e.g. with arr.slice(1) etc. and I do not want to chop off the first element of the array e.g. with arr.shift().
For example, given the array [3, 5, 8] the rest of the array is [5, 8] and if the rest of the array is changed, e.g. by an assignment (a destructive operation), the array also changes. I just figured out that as a test that proves the rest is the rest of the array but not a new array consists of the rest of the elements of the array.
Note: The following code example is to describe what I want, but not specifically what I want to do (i.e. not the operations I want to perform). What I want to do is in the every algorithm at the bottom.
var arr = [3, 5, 8];
var rest = rest(arr); // rest is [5, 8]
rest.push(13); // rest is [5, 8, 13] and hence the arr is [3, 5, 8, 13]
An example I possibly need this and I would want to have it is following algorithm and many other I am writing in that GitHub organization, in both of which I use always arr.slice(1):
function every(lst, f) {
if (lst.length === 0) {
return false;
} else {
if (f(lst[0]) === true) {
return every(lst.slice(1), f);
} else {
return false;
}
}
}
I think having what I ask for instead of arr.slice(1) would keep the memory usage of such algorithms and retain the recursive-functional style I want to employ.
No, this is generally not possible. There are no "views on" or "pointers to" normal arrays1.
You might use a Proxy to fake it, but I doubt this is a good idea.
1: It's trivial to do this on typed arrays (which are views on a backing buffer), but notice that you cannot push to them.
I possibly need this and I would want to have it for recursive-functional style algorithms where I currently use arr.slice(1) but would prefer to keep memory usage low
Actually, all of these implementations do have low memory usage - they don't allocate more memory than the input. Repeatedly calling slice(1) does lead to high pressure on the garbage collector, though.
If you were looking for better efficiency, I would recommend to
avoid recursion. JS engines still didn't implement tail recursion, so recursion isn't cheap.
not to pass around (new copies of) arrays. Simply pass around an index at which to start, e.g. by using an inner recursive function that closes over the array parameter and accesses array[i] instead of array[0]. See #Pointy's updated answer for an example.
If you were looking for a more functional style, I would recommend to use folds. (Also known as reduce in JavaScript, although you might need to roll your own if you want laziness). Implement your algorithms in terms of fold, then it's easy to swap out the fold implementation for a more efficient (e.g. iterative) one.
Last but not least, for higher efficiency while keeping a recursive style you can use iterators. Their interface might not look especially functional, but if you insist you could easily create an immutable wrapper that lazily produces a linked list.
please test this function
function rest(arr) {
var a = arr.slice(1);
a.push = function() {
for (var i = 0, l = arguments.length; i < l; i++) {
this[this.length] = arguments[i];
arr[this.length] = arguments[i];
}
return this.length;
};
return a;
}
Based on the code posted in the update to the question, it's clear why you might want to be able to "alias" a portion of an array. Here is an alternative that is more typical of how I would solve the (correctly) perceived efficiency problem with your implementation:
function every(lst, f) {
function r(index) {
if (index >= lst.length)
return true; // different from OP, but I think correct
return f(lst[index]) && r(index+1);
}
return r(0);
}
That is still a recursive solution to the problem, but no array copy is made; the array is not changed at all. The general pattern is common even in more characteristically functional programming languages (Erlang comes to mind personally): the "public" API for some recursive code is augmented by an "internal" or "private" API that provides some extra tools for keeping track of the progress of the recursion.
original answer
You're looking for Array.prototype.shift.
var arr = [1, 2, 3];
var first = arr.shift();
console.log(first); // 1
console.log(arr); // [2, 3]
This is a linear time operation: the execution cost is relative to the length of the original array. For most small arrays that does not really matter much, but if you're doing lots of such work on large arrays you may want to explore a better data structure.
Note that with ordinary arrays it is not possible to create a new "shadow" array that overlaps another array. You can do something like that with typed arrays, but for general purpose use in most code typed arrays are somewhat awkward.
The first limitation of typed arrays is that they are, of course, typed, which means that the array "view" onto the backing storage buffer gives you values of only one consistent type. The second limitation is that the only available types are numeric types: integers and floating-point numbers of various "physical" (storage) sizes. The third limitation is that the size of a typed array is fixed; you can't extend the array without creating a new backing buffer and copying.
Such limitations would be quite familiar to a FORTRAN programmer of course.
So to create an array for holding 5 32-bit integers, you'd write
var ints = new Int32Array(5);
You can put values into the array just like you put values into an ordinary array, so long as you get the type right (well close enough):
for (let i = 0; i < 5; i++)
ints[i] = i;
console.log(ints); // [0, 1, 2, 3, 4]
Now: to do what the OP asked, you'd grab the buffer from the array we just created, and then make a new typed array on top of the same buffer at an offset from the start. The offsets when doing this are always in bytes, regardless of the type used to create the original array. That's super useful for things like looking at the individual parts of a floating point value, and other "bit-banging" sorts of jobs, though of course that doesn't come up much in normal JavaScript coding. Anyway, to get something like the rest array from the original question:
var rest = new Int32Array(ints.buffer, 4);
In that statement, the "4" means that the new array will be a view into the buffer starting 4 bytes from the beginning; 32-bit integers being 4 bytes long, that means that the new view will skip the first element of the original array.
Since JavaScript can't do this, the only real solution to your problem is WebAssembly. Otherwise use Proxy.

what is use of adding length property to objects in javascript?

Array do support length property as well as string does, but objects don't inherently have a length property.
in case we add a length properly as below.
{"a":0,"b":0,length:2}
what is the use case scenario for above code
An object doesn't have a length, per se. It depends on what this length represents.
For example, in the code you posted, it's not immediately obvious why the length is 4, but it might make sense in the context of what that object actually represents.
Here are both methods of getting the length.
You'll notice if you keep track of your own length the display code is a bit shorter but you need a whole function to add a new key, you'd even need another function to remove them.
object.keys changes the keys into an array which we can get the length from this, of course, take a few milliseconds more as it has to do the convert.
I generally run with the assumption a computer is going to make fewer mistakes than me so, if I can, I should load as much work as possible onto it.
// initial set up
let obj1 = {"a":0,"b":0};
let obj2 = {"a":0,"b":0,length:2};
// initial lengths
console.log("obj1: "+Object.keys(obj1).length);
console.log("obj2: "+obj2.length);
// adding standard way
obj1["c"] = 0;
// adding to accomidate with length
function addObj2(key, value) {
obj2[key] = value;
obj2.length++;
}
addObj2("c",0);
console.log("--");
// new lengths
console.log("obj1: "+Object.keys(obj1).length);
console.log("obj2: "+obj2.length);
I hope this makes sense.

Do arrays with gaps in their indices entail any benefits that compensate their disadvantages

In Javascript arrays may have gaps in their indices, which should not be confused with elements that are simply undefined:
var a = new Array(1), i;
a.push(1, undefined);
for (i = 0; i < a.length; i++) {
if (i in a) {
console.log("set with " + a[i]);
} else {
console.log("not set");
}
}
// logs:
// not set
// set with 1
// set with undefined
Since these gaps corrupt the length property I'm not sure, if they should be avoided whenever possible. If so, I would treat them as edge case and not by default:
// default:
function head(xs) {
return xs[0];
}
// only when necessary:
function gapSafeHead(xs) {
var i;
for (i = 0; i < xs.length; i++) {
if (i in xs) {
return xs[i];
}
}
}
Besides the fact that head is very concise, another advantage is that it can be used on all array-like data types. head is just a single simple example. If such gaps need to be considered throughout the code, the overhead should be significantly.
This is likely to come up in any language that overloads hash tables to provide something that colloquially is called an "array". PHP, Lua and JavaScript are three such languages. If you depend on strict sequential numeric array behavior, then it will be an inconvenience for you. More generally, the behavior provides conveniences as well.
Here's a classic algorithm question: to delete a member from the middle of a data structure, which data structure is "better": A linked list or an array?
You're supposed to say "linked list", because deleting a node from a linked list doesn't require you to shift the rest of the array down one index. But linked lists have other pitfalls, so is there another data structure we can use? You can use a sparse array*.
In many languages that provide this hashy type of arrays, removing any arbitrary member of the array will change the length. Unfortunately, JavaScript does not change the length, so you lose out a little there. But nevertheless, the array is "shorter", at least from the Object.keys perspective.
*Many sparse arrays are implemented using linked lists, so don't apply this too generally. In these languages, though, they're hash tables with predictable ordered numeric keys.
Of course, the question is a subjective one, but I argue that the gaps should certainly be avoided, if possible. Arrays are special Javascript objects with very specific purposes. You can totally hack on arrays, manipulate the length property, add properties with keys other than numbers (e.g myArray["foo"] = "bar"), but these mostly devolve into antipatterns. If you need some special form of pseudo-array, you can always just code it yourself with a regular object. After all, typeof [] === "object"
It's not like gaps inherently break your code, but I would avoid pursuing them intentionally.
Does that answer your question?

Can I make a "Virtual Array" in JavaScript?

I'm calling a JavaScript function that wants an array of things to display. It displays a count, and displays the items one by one. Everything works when I pass it a normal JavaScript array.
But I have too many items to hold in memory at once. What I'd like to do, is pass it an object with the same interface as an array, and have my method(s) be called when the function tries to access the data. And in fact, if I pass the following:
var featureArray = {length: count, 0: func(0)};
then the count is displayed, and the first item is correctly displayed. But I don't want to assign all the entries, or I'll run out of memory. And the function currently crashes when the user tries to display the second item. I want to know when item 1 is accessed, and return func(1) for item 1, and func(2) for item 2, etc. (i.e., delaying the creation of the item until it is requested).
Is this possible in JavaScript?
If I understand correctly, this would help:
var object = {length: count, data: function (whatever) {
// create your item
}};
Then, instead of doing array[1], array[2], et cetera, you'd do object.data(1), object.data(2), and so on.
Since there seems to be a constraint that the data must be accessed using array indexing via normal array indexing arr[index] and that can't be changed, then the answer is that NO, you can't override array indexing in Javascript to change how it works and make some sort of virtual array that only fetches data upon demand. It was proposed for ECMAScript 4 and rejected as a feature.
See these two other posts for other discussion/confirmation:
How would you overload the [] operator in Javascript
In javascript, can I override the brackets to access characters in a string?
The usual way to solve this problem would be to switch to using a method such as .get(n) to request the data and then the implementor of .get() can virtualize however much they want.
P.S. Others indicate that you could use a Proxy object for this in Firefox (not supported in other browsers as far as I know), but I'm not personally familiar with Proxy objects as it's use seems rather limited to code that only targets Firefox right now.
Yes, generating items on the go is possible. You will want to have a look at Lazy.js, a library for producing lazily computed/loaded sequences.
However, you will need to change your function that accepts this sequence, it will need to be consumed differently than a plain array.
If you really need to fake an array interface, you'd use Proxies. Unfortunately, it is only a harmony draft and currently only supported in Firefox' Javascript 1.8.5.
Assuming that the array is only accessed in an iteration, i.e. starting with index 0, you might be able to do some crazy things with getters:
var featureArray = (function(func) {
var arr = {length: 0};
function makeGetter(i) {
arr.length = i+1;
Object.defineProperty(arr, i, {
get: function() {
var val = func(i);
Object.defineProperty(arr, i, {value:val});
makeGetter(i+1);
return val;
},
configurable: true,
enumerable: true
});
}
makeGetter(0);
return arr;
}(func));
However, I'd recommend to avoid that and rather switch the library that is expecting the array. This solution is very errorprone if anything else is done with the "array" but accessing its indices in order.
Thank you to everyone who has commented and answered my original question - it seems that this is not (currently) supported by JavaScript.
I was able to get around this limitation, and still do what I wanted. It uses an aspect of the program that I did not mention in my original question (I was trying to simplify the question), so it is understandable that other's couldn't recommend this. That is, it doesn't technically answer my original question, but I'm sharing it in case others find it useful.
It turns out that one member of the object in each array element is a callback function. That is (using the terminology from my original question), func(n) is returning an object, which contains a function in one member, which is called by the method being passed the data. Since this callback function knows the index it is associated with (at least, when being created by func(n)), it can add the next item in the array (or at least ensure that it is already there) when it is called. A more complicated solution might go a few ahead, and/or behind, and/or could cleanup items not near the current index to free memory. This all assumes that the items will be accessed consecutively (which is the case in my program).
E.g.,
1) Create a variable that will stay in scope (e.g., a global variable).
2) Call the function with an object like I gave as an example in my original question:
var featureArray = {length: count, 0: func(0)};
3) func() can be something like:
function func(r) {
return {
f : function() {featureArray[r + 1] = func(r + 1); DoOtherStuff(r); }
}
}
Assuming that f() is the member with the function that will be called by the external function.

What use does the JavaScript forEach method have (that map can't do)?

The only difference I see in map and foreach is that map is returning an array and forEach is not. However, I don't even understand the last line of the forEach method "func.call(scope, this[i], i, this);". For example, isn't "this" and "scope" referring to same object and isn't this[i] and i referring to the current value in the loop?
I noticed on another post someone said "Use forEach when you want to do something on the basis of each element of the list. You might be adding things to the page, for example. Essentially, it's great for when you want "side effects". I don't know what is meant by side effects.
Array.prototype.map = function(fnc) {
var a = new Array(this.length);
for (var i = 0; i < this.length; i++) {
a[i] = fnc(this[i]);
}
return a;
}
Array.prototype.forEach = function(func, scope) {
scope = scope || this;
for (var i = 0, l = this.length; i < l; i++) {
func.call(scope, this[i], i, this);
}
}
Finally, are there any real uses for these methods in JavaScript (since we aren't updating a database) other than to manipulate numbers like the following?
alert([1,2,3,4].map(function(x){ return x + 1})); // This is the only example I ever see of map in JavaScript.
The essential difference between map and forEach in your example is that forEach operates on the original array elements, whereas map explicitly returns a new array as a result.
With forEach you are taking some action with -- and optionally changing -- each element in the original array. The forEach method runs the function you provide for each element, but returns nothing (undefined). On the other hand, map walks through the array, applies a function to each element, and emits the result as a new array.
The "side effect" with forEach is that the original array is being changed. "No side effect" with map means that, in idiomatic usage, the original array elements are not changed; the new array is a one-to-one mapping of each element in the original array -- the mapping transform being your provided function.
The fact that there's no database involved does not mean that you won't have to operate on data structures, which, after all, is one of the essences of programming in any language. As for your last question, your array can contain not only numbers, but objects, strings, functions, etc.
The main difference between the two methods is conceptual and stylistic: You use forEach when you want to do something to or with each element of an array (doing "with" is what the post you cite meant by "side-effects", I think), whereas you use map when you want to copy and transform each element of an array (without changing the original).
Because both map and forEach call a function on each item in an array, and that function is user-defined, there is almost nothing you can do with one and not with the other. It's possible, though ugly, to use map to modify an array in-place and/or do something with array elements:
var a = [{ val: 1 }, { val: 2 }, { val: 3 }];
a.map(function(el) {
el.val++; // modify element in-place
alert(el.val); // do something with each element
});
// a now contains [{ val: 2 }, { val: 3 }, { val: 4 }]
but much cleaner and more obvious as to your intent to use forEach:
var a = [{ val: 1 }, { val: 2 }, { val: 3 }];
a.forEach(function(el) {
el.val++;
alert(el.val);
});
Especially if, as is usually the case in the real world, el is a usefully human-readable variable:
cats.forEach(function(cat) {
cat.meow(); // nicer than cats[x].meow()
});
In the same way, you can easily use forEach to make a new array:
var a = [1,2,3],
b = [];
a.forEach(function(el) {
b.push(el+1);
});
// b is now [2,3,4], a is unchanged
but it's cleaner to use map:
var a = [1,2,3],
b = a.map(function(el) {
return el+1;
});
Note as well that, because map makes a new array, it likely incurs at least some performance/memory hit when all you need is iteration, particularly for large arrays - see http://jsperf.com/map-foreach
As for why you'd want to use these functions, they're helpful any time you need to do array manipulation in JavaScript, which (even if we're just talking about JavaScript in a browser environment) is pretty often, almost any time you're accessing an array that you're not writing down by hand in your code. You might be dealing with an array of DOM elements on the page, or data pulled from an Ajax request, or data entered in a form by the user. One common example I run into is pulling data from an external API, where you might want to use map to transform the data into the format you want and then use forEach to iterate over your new array in order to display it to your user.
The voted answer (from Ken Redler) is misleading.
A side effect in computer science means that a property of a function/method alters a global state [Wikipedia]. In some narrow sense, this may also include reading from a global state, rather than from arguments. In imperative or OO programming, side effects appear most of the time. And you are probably making use of it without realizing.
The significant difference between forEach and map is that map allocates memory and stores the returning value, while forEach throws it away. See the ECMA specification for more information.
As for the reason why people say forEach is used when you want a side effect is that the return value of forEach is always undefined. If it has no side effect (does not change global state), then the function is just wasting CPU time. An optimizing compiler will eliminate this code block and replace the it with the final value (undefined).
By the way, it should be noted that JavaScript has no restriction on side effects. You can still modify the original array inside map.
var a = [1,2,3]; //original
var b = a.map( function(x,i){a[i] = 2*x; return x+1} );
console.log("modified=%j\nnew array=%j",a,b);
// output:
// modified=[2,4,6]
// new array=[2,3,4]
This is a beautiful question with an unexpected answer.
The following is based on the official description of Array.prototype.map().
There is nothing that forEach() can do that map() cannot. That is, map() is a strict super-set of forEach().
Although map() is usually used to create a new array, it may also be used to change the current array. The following example illustrates this:
var a = [0, 1, 2, 3, 4], mapped = null;
mapped = a.map(function (x) { a[x] = x*x*x; return x*x; });
console.log(mapped); // logs [0, 1, 4, 9, 16] As expected, these are squares.
console.log(a); // logs [0, 1, 8, 27, 64] These are cubes of the original array!!
In the above example, a was conveniently set such that a[i] === i for i < a.length. Even so, it demonstrates the power of map(), and in particular its ability to change the array on which it is called.
Note1:
The official description implies that map() may even change length the array on which it is called! However, I cannot see (a good) reason to do this.
Note 2:
While map() map is a super-set of forEach(), forEach() should still be used where one desires the change a given array. This makes your intentions clear.
You can use map as though it were forEach.
It will do more than it has to, however.
scope can be an arbitrary object; it's by no means necessarily this.
As for whether there are real uses for map and forEach, as well to ask if there are real uses for for or while loops.
While all the previous questions are correct, I would definitely make a different distinction. The use of map and forEach can imply intent.
I like to use map when I am simply transforming the existing data in some way (but want to make sure the original data is unchanged).
I like to use forEach when I am modifying the collection in place.
For instance,
var b = [{ val: 1 }, { val: 2 }, { val: 3 }];
var c = b.map(function(el) {
return { val: el.val + 1 }; // modify element in-place
});
console.log(b);
// [{ val: 1 }, { val: 2 }, { val: 3 }]
console.log(c);
// [{ val: 3 }, { val: 4 }, { val: 5 }]
My rule of thumb being making sure when you map you are always creating some new object/value to return for each element of the source list and returning it rather than just performing some operation on each element.
Unless you have any real need to modify the existing list, it doesn't really make sense to modify it in place and fits better into functional/immutable programming styles.
TL;DR answer --
map always returns another array.
forEach does not. It is up to you to decide what it does. Return an array if you want or do something else if you don't.
Flexibility is desirable is certain situations. If it isn't for what you are dealing with then use map.
Others have already posted about your main question regarding the difference between the functions. But for...
are there any real uses for these methods in JavaScript (since we aren't updating a database) other than to manipulate numbers like this:
...it's funny you should ask. Just today I wrote a piece of code that assigns a number of values from a regular expression to multiple variables using map for transformation.
It was used to convert a very complicated text-based structure into visualizable data ... but for simplicity's sake, I shall offer an example using date strings, because those are probably more familiar for everyone (though, if my problem had actually been with dates, instead of map I would've used Date-object, which would've done the job splendidly on its own).
const DATE_REGEXP = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})\.(\d{3})Z$/;
const TEST_STRING = '2016-01-04T03:20:00.000Z';
var [
iYear,
iMonth,
iDay,
iHour,
iMinute,
iSecond,
iMillisecond
] = DATE_REGEXP
// We take our regular expression and...
.exec(TEST_STRING)
// ...execute it against our string (resulting in an array of matches)...
.slice(1)
// ...drop the 0th element from those (which is the "full string match")...
.map(value => parseInt(value, 10));
// ...and map the rest of the values to integers...
// ...which we now have as individual variables at our perusal
console.debug('RESULT =>', iYear, iMonth, iDay, iHour, iMinute, iSecond, iMillisecond);
So ... while this was just an example - and only did a very basic transformation for the data (just for sake of example) ... having done this without map would've been a much more tedious task.
Granted, it is written in a version of JavaScript that I don't think too many browsers support yet (at least fully), but - we're getting there. If I needed to run it in browser, I believe it would transpile nicely.

Categories

Resources