I have a string of data that is a string of x,y pairs like this:
[
[0.519999980926514, 0.0900000035762787],
[0.529999971389771, 0.689999997615814],
[0.519999980926514, 2.25],
[0.850000023841858, 2.96000003814697],
[1.70000004768372, 3.13000011444092],
[1.91999995708466, 3.33999991416931],
[0.839999973773956, 3.5],
[1.57000005245209, 3.38000011444092],
[0.819999992847443, 3.00999999046326],
[1.69000005722046, 2.99000000953674],
[2.98000001907349, 3.23000001907349],
[0.509999990463257, 1.11000001430511],
[0.670000016689301, 1.35000002384186],
[0.660000026226044, 1.26999998092651],
[0.689999997615814, 0.0500000007450581],
[1.30999994277954, 0.0599999986588955],
[0.569999992847443, 0.0299999993294477],
[0.629999995231628, 0.0399999991059303],
[0.720000028610229, 0.0399999991059303],
[0.639999985694885, 0.0399999991059303],
[0.540000021457672, 0.0399999991059303],
[0.550000011920929, 0.0500000007450581],
[0.850000023841858, 0.0399999991059303],
[0.610000014305115, 0.0199999995529652],
[0.509999990463257, 0.0500000007450581],
[0.610000014305115, 0.0599999986588955],
[0.5, 0.0599999986588955],
[0.639999985694885, 0.0599999986588955]
]
What I want to do is find the max and min in each pair.
Is there any way of doing this without going through the entire string and examining each element in the pair?
There is no way to outperform O(n) operations (where n is the number of pairs) on this problem.
In some cases, it is possible to find the maximum in less time, however all algorithms require at least 1 comparison (which is the number of comparisons needed to determine the maximum of a pair).
To do what you want, you ought to turn to JavaScript's wonderful map and apply functions:
function maxOfSubArrays(input) {
// assumes `input` is an array of n-element arrays
return input.map(function(el) { return Math.max.apply(Math, el); });
}
map returns a new array with each element set to the return value of the function applied to an element in the original array (ie mapped[i] = f(input[i])). apply calls a function , unpacking the provided array as the arguments (so Math.max.apply(Math, [1, 2]) is the same as Math.max(1, 2)).
To find the minimum rather than the maximum, use Math.min. To get both, it is easiest to simply return [Math.min..., Math.max...].
EDIT: If I understand your comment correctly, you want to treat it like an nx2 matrix, where n is the number of pairs (also: number of rows). Then, you want to find the maximum of each column. This is relatively easy to do with apply and map:
function maxOfColumns(input) {
return [Math.max.apply(Math, input.map(function(el) { return el[0]; })),
Math.max.apply(Math, input.map(function(el) { return el[1] }))];
}
An attentive reader will note that this creates a copy of the entire data set. For large data sets, this can be a problem. In such a case, using map to construct the columns would not be ideal. However, for most use cases there will not be a significant performance difference.
Here is a JSFiddle that demonstrates both variants: http://jsfiddle.net/utX53/ Look in the JS Console to see the results (Ctrl-Shift-J on Chrome in Win/Lin)
There does not seem to be any particular structure that could be used to speed up the process, which means that O(n) is still the fastest this can be done.
A final word: maxOfColumns can be trivially extended to handle an arbitrary number of columns. I leave it to the reader to figure out how (mostly because it is much less readable than the above).
Related
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.
I believe it's quadratic O(n^2) but not 100% sure due to uncertainty of how the .filter() and .map() operations work in JavaScript.
The big question I have is whether the entire filter() operation completes before starting a single map() operation, or if it's smart enough to perform the map() operation while it's already iterating within the filter() operation.
The method
function subscribedListsFromSubscriptions(subscriptions: Subscription[]) {
return new Set(listSubscriptions.filter((list) => {
return list.subscribed;
}).map((list) => {
return list.list_id;
}));
}
Example input data
let subscriptions = [ {
list_id: 'abc',
subscribed: false
}, {
list_id: 'ghi',
subscribed: false
}];
From what I see
It appears to be:
filter() for each element of subscriptions - time n
map() for each remaining element - time n (at maximum)
new Set() for each remaining element - time n (at maximum)
For the new Set() operation, I'm guessing it's creating a new object and adding each element to the created instance.
If there were many duplicates in data, one might expect the efficiency to increase. But we don't expect many duplicates in data, and from my understanding of 'Big O', the maximal limit is what's used.
From this analysis, I'm expecting the time complexity to be either O(n^2) or O(n^3). But as stated, I'm unsure of how to interpret it for certain.
Any help in this would be greatly appreciated. Thanks in advance!
I think your interpretation of the order of operations is correct: filter, then map, then create a Set.
However, in order for this algorithm to reach O(n^2), you would have to create a nested loop, for example:
create the Set for each element of the array
compare each element witch each other element in the array.
This is not the case here. In the worst case scenario (no duplicates), the algorithm will iterate the input array three times, meaning the O(3*n) complexity which is still linear, not quadratic.
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.
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.
var data = [{"speed": 210},{"speed": 50},{"speed": 160}];
I want to get the maximum speed from data, so I am doing the following:
var max = Math.max(data[0]['speed'], data[1]['speed'], data[2]['speed']);
This is neither elegant or scalable (assume there could be an arbitrary amount of objects in the array).
NOTE: I have tagged jQuery as I have that on the page (i.e. if you can suggest a clever use of .grep or something it is available to me - although I'm assuming that's overkill?).
You could map the objects speed properties into an array, and then use Math.max with apply() to get the largest number
Math.max.apply( null, data.map(function(x) {return x.speed}) );
FIDDLE