Related
I trying to came up algorithm in js for sorting from closest to farthest by given number, for example (number: 5.6666, array: [-1, 9, 4, 10, 11, 0]) should return [4, 9, 10, 0, 11, -1].Any idea how approach to the problem? A little gotcha actually my array is array of objects and I need sort by certain key in object. In docs said, that should use array.sort() with compare function, but I don't understand how implement this function.
The sort() function of Array can take a function:
[1,2,3].sort((a, b) => /* do something */)
Each time, you should return a value. A negative number will mean a comes before b. A positive number means b comes before a. 0 means they are equal.
If you want distance to the number, you want the absolute value, with Math.abs(). Assuming the key on the object is value, you can put it all together:
const target = 5;
const values = [{ value: -100 }, { value: 1 }, { value: 4 }, { value: 6 }, { value: 10 }];
const result = values.sort(({ value: a }, { value: b }) =>
Math.abs(target - a) - Math.abs(target - b));
console.log(result);
I used some ES6 destructuring to make it a bit cleaner by pulling the value out in the parameters.
If you wanted to just have the values remaining (instead of the objects), you can either use map() after the fact (or before).
Note, in the case of 2 numbers being equidistant from the target (in my example, 4 and 6 are both 1 away from the target), you can't guarantee which will come first. If it matters to you, you'll want to add some extra logic to hand that scenario.
Using sort, you can check each of their distances from your number.
var num = 5.666
var arr = [-1, 9, 4, 10, 11, 0]
arr.sort(function(a, b){
return Math.abs(num-a) - Math.abs(num-b);
});
console.log(arr)
Use array.sort and get the difference of each number from the input value given
var inputArray = [-1, 9, 4, 10, 11, 0],
input = 5;
var closest = inputArray.sort(function(a, b){
return Math.abs(input-a) - Math.abs(input-b);
});
console.log(closest);
I'm trying to understand the following solution for finding the largest adjacent product in any given array.
Example:
For inputArray = [3, 6, -2, -5, 7, 3], the output should be
adjacentElementsProduct(inputArray) = 21.
7 and 3 produce the largest product.
Possible solution in JS:
function adjacentElementsProduct(arr) {
return Math.max(...arr.slice(1).map((x,i)=>[x*arr[i]]))
}
I am having a hard time understanding two things:
What do the three dots exactly do and how does this get passed into the function? Is there any way to write this in a more understandable way? I know that is the "spread syntax" feature in ES6, but still don't understand completely.
Why do we insert "1" as argument to slice? My first though was to input "0", because we want to start at the start, then loop through everything, and see which adjacent product is the largest.
I'd appreciate any advice, links and explanations.
Thanks.
Cheers!
1. What do the three dots exactly do and how does this get passed into the function? Is there any way to write this in a more understandable way? I know that is some kind of "spread" feature in ES6, but still don't understand completely.
The Math#max needs a list of numbers as parameters, and map produces an array. The spread syntax is used to convert an array to be expanded to a list of parameters.
const arr = [1, 2, 3];
console.log('max on array', Math.max(arr));
console.log('max on list of parameters', Math.max(...arr));
In this case you can use Function#apply to convert the array to a list of parameters. I find it less readable, however.
const arr = [1, 2, 3];
console.log(Math.max.apply(Math, arr));
2. Why do we insert "1" as argument to slice? My first though was to input "0", because we want to start at the start, then loop through everything, and see which adjacent product is the largest.
Lets break down the iteration order of the 2 arrays.
[3, 6, -2, -5, 7, 3] // inputArray
[6, -2, -5, 7, 3] // inputArray.slice(1)
Now on each iteration of inputArray.slice(1):
x: 6, i = 0, arr[0] = 3
x: -2, i = 1, arr[1] = 6
x: -5, i = 2, arr[2] = -2
Since the inputArray.slice(1) array starts from the 2nd element of the inputArray, the index (i) points to the 1st element of the inputArray. And the result is an array of products of 2 adjacent numbers.
var biggestProduct = inputArray[0] * inputArray[1];
for (i=0; i<inputArray.length-1 ; ++i)
{
console.log(biggestProduct)
if ((inputArray[i] * inputArray[i+1] ) > biggestProduct)
{
biggestProduct = inputArray[i] * inputArray[i+1]
}
}
return biggestProduct;
Note: I've declared a variable that consists of 2 input arrays with index number then starts a for loop that indicates input array with his index number, so by that he will go throw all the index number of the array (one of them raised by one so that they won't be at the same value). and at the end of the code, you have the if statement.
You may simply do as follows;
function getNeigboringMaxProduct([x,...xs], r = -Infinity){
var p = x * xs[0];
return xs.length ? getNeigboringMaxProduct(xs, p > r ? p : r)
: r;
}
var arr = [3, 6, -2, -5, 7, 3],
res = getNeigboringMaxProduct(arr);
console.log(res);
Please help, I've been looking for an answer for far too long.
I'm trying to create an array using push method to insert the numbers
0 to 10 into positions 0 through 10 of the numbers array you just initialized above.
I did this:
var numbers = [];
for(var i = 0; i < 10; i++) {
numbers.push(i);
console.log(numbers);
And got this result, which I think is correct but not 100% sure:
[ 0 ]
[ 0, 1 ]
[ 0, 1, 2 ]
[ 0, 1, 2, 3 ]
[ 0, 1, 2, 3, 4 ]
[ 0, 1, 2, 3, 4, 5 ]
[ 0, 1, 2, 3, 4, 5, 6 ]
[ 0, 1, 2, 3, 4, 5, 6, 7 ]
[ 0, 1, 2, 3, 4, 5, 6, 7, 8 ]
[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
0
Then I am to test the array push method by printing the sum of the values at
position 3 and 6 of the array (use the console.log() function to print to the console).
The outputted value should be 9.
I am so stuck on this point and cannot find a sample anywhere of how to accomplish this. I thought it might be something like:
console.log(numbers(sum[3, 6]);
If you want to have a sum() function, then try the following:
function sum(x, y) {
return x + y;
}
console.log(sum(numbers[3], numbers[6]));
Here's a Fiddle: https://jsfiddle.net/7181h1ok/
To sum the values of two indices of an array, you use the + addition operator in the following fashion:
var numbers = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ];
var sum = numbers[3] + numbers[6]; //adds the value in index 3 of the numbers array to the value in index 6 of the numbers array.
console.log(sum); //prints the sum to the console.
As a note, if you are unfamiliar with JavaScript and/or its operators, there's useful documentation at w3schools that can get you started.
First, let's convert your code to a little bit better style:
const numbers = [];
for (let i = 0; i < 10; i++) {
numbers.push(i);
console.log(numbers);
}
Note: I made numbers a const instead of a var, since you don't change it. I also made i a let binding instead of a var. In general, var is a legacy and should never be used. Use const instead if at all possible, otherwise use let.
Also, I inserted a space after the for keyword. It is generally recommended to separate the parentheses which enclose the header of a control structure keyword (if, while, for, etc.) with a space, to make it visually distinct from the parentheses for the argument list of a function call, which has no space.
Secondly: Your result is not correct. (Hint: how many numbers are the numbers 0 to 10?) It should include the numbers 0 to 10, but it only includes the numbers 0 to 9. You have what is generally called an off-by-one-error. These errors are very common when dealing with trying to manage loop indices manually. This is the fix:
const numbers = [];
for (let i = 0; i <= 10; i++) {
// ↑
numbers.push(i);
console.log(numbers);
}
Most modern programming languages have better alternatives than dealing with loop indices manually in the form of higher-level abstractions such as iterators, maps, and folds. Unfortunately, ECMAScript doesn't have a Range datatype, otherwise this could simply be expressed as converting a Range to an Array.
If ECMAScript did have a Range datatype, it could for example look like one of these:
const numbers = Range(0, 10).toArray()
const numbers = Array.from(Range(0, 10))
Here is an alternative for creating the numbers Array that doesn't involve manually managing loop indices, but still requires knowing that 0 to 10 are 11 numbers:
const numbers = Array.from({length: 11}, (_, i) => i)
If you want to add the numbers at indices 3 and 6, you can simply dereference indices 3 and 6 and add the results:
console.log(numbers[3] + numbers[6])
In the comments, you asked how you would add up all numbers in the Array. Combining the elements of a collection using a binary operator is called a fold or reduce, and ECMAScript supports it out-of-the-box:
console.log(numbers.reduce((acc, el) => acc + el));
Note how there is no explicit loop, thus no explicit management of loop indices. It is simply impossible to make an off-by-one-error here.
It will be: console.log((+numbers[3]) + (+numbers[6]));
Typically, it should be console.log(numbers[3] + numbers[6]); but there's sometimes a issue that results in 36 instead of 9. The extra + signs tell javascript that it is a number.
NOTE: Remember that the first number is numbers[0]. The array starts with 0!
I want to return an array that that maps some filtered elements - but I want to keep the non-filtered elements where they are.
i.e. Is there an easy way to do this?:
array
.filter(
function(element){
// some test
}
)
.map(
function(element){
// some mapping
}
)
The closest solution I've come up with is something along the lines of:
array
.map(
function(value, index){
if (<test>) {
return <mapping>(value);
}
}
)
but I feel this somewhat breaks the spirit of functional programming.
I'm not asking for a specific language implementation, although an example in Scala or JavaScript would be nice.
EDIT: Here's a concrete example of what I'm looking for:
[1,2,3,4,11,12]
Mapping all elements to element*10, for all elements in array which are greater than 10, should yield
[1,2,3,4,110,120]
EDIT2: I apologize for using the word "mutate." I did not mean mutate the original array - I was thinking more along the lines of mutating a copy of the array.
It's not really going to be functional if you're using a mutable collection. But you can use transform in Scala:
scala> val a = Array(1,2,3,4,11,12)
a: Array[Int] = Array(1, 2, 3, 4, 11, 12)
scala> a.transform {i => if(i > 10) i * 10 else i}
res10: scala.collection.mutable.WrappedArray[Int] = WrappedArray(1, 2, 3, 4, 110, 120)
edit:
If you want filter and map separated, use a view:
scala> a
res22: Array[Int] = Array(1, 2, 3, 4, 11, 12)
scala> a.view.filter(_ > 10).transform(_ * 10)
res23: scala.collection.mutable.IndexedSeqView[Int,Array[Int]] = SeqViewF(...)
scala> a
res24: Array[Int] = Array(1, 2, 3, 4, 110, 120)
Is collect what you are after?
scala> List(2, 3, 5, 6, 9).filter(_ < 5).map(_ * 100)
res30: List[Int] = List(200, 300)
scala> List(2, 3, 5, 6, 9).collect { case i if i < 5 => i * 100 }
res31: List[Int] = List(200, 300)
You could provide your filter and map function to a 'combining' function; I've tried an example on http://jsfiddle.net/xtofl/UDbyL/.
The idea is to apply the 'mapping' (which I would call inplace mapping) to all elements conforming to the filtering predicate in the original array.
Although these sorts of operations are possible in principle, the Scala library does not provide them.
You can build your own using indices (or views on indices):
scala> val a = Array(1,2,3,4,5)
a: Array[Int] = Array(1, 2, 3, 4, 5)
scala> a.indices.view.filter(i=>a(i)%2==0).foreach(i=>a(i)=0)
scala> a
res1: Array[Int] = Array(1, 0, 3, 0, 5)
It's slightly awkward, but usually a little better than the if-statement version (in that at least you can see the filter and assignment steps separately).
Hej jiaweihli
the easiest solution is to reassign it to the reference ... ie mutating the reference
and not the data. This has some benefits if the reference is in other places you
are not mutating it under there noses.
EX:
x = x.filter(filterOpp);
ps! the second example there dosent work.
GL
The problem you are having is that you are thinking of filtering, and filtering is not what you want. If you don't want to remove elements, it is not a filter.
All you need is a simple map:
array.map(x => if(x > 10) x * 10 else x)
Or, if you think your conditions are too complex,
array.map {
case x if x > 10 => x * 10
case x => x
}
How about something like this: (psuedo javascript)
filteredMap = function(element) {
if(filterFunc(element)){
return mapFunc(element);
}
return element;
}
array = array.map(filteredMap)
Unless you explicitly are required to mutate the array (which isn't "functional") this should get you what you want.
What would be the tersest way to create this array:
var x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
For example, a for loop:
var x = [];
for (var i=1;i<=20;i++) {
x.push(i);
}
Or a while loop:
var x = [], i = 1, endInt = 20;
while (i <= endInt) {
x.push(i);
i++;
}
Would there be other examples that would be terser -- in other words -- less code? I'm thinking of things like in Ruby where the equivalent code I believe would be as simple as 1..20. I'm not aware of syntax like that in JavaScript but I'm wondering if there are shorter ways to do that same thing.
UPDATE: I wasn't thinking of removing semicolons or var for answers in the question, but I have to admit the question implies that. I am more curious about algorithms than shaving bytes. Sorry if I was unclear! Also, making it into a function is simple enough, just slap function range(start, end) { /* guts here */ } around it and you're there. The question is are there novel approaches to the "guts."
Favorite method
Update Sep13,2015:
Just came up with this new method which works with browsers which support the ES6 standard:
> Array(5).fill().map((x,i)=>i)
[0, 1, 2, 3, 4]
Note the above does a tiny bit of extra work (fills with undefined) but is relatively minor vis-a-vis the speedup you can achieve by using a for loop, and if you forget the .fill you may be confused why your array is mysteriously [empty x 5]. You can encapsulate the above as a custom function, or alternatively use a somewhat more intended method:
> Array.from(Array(5),(x,i)=>i)
[0, 1, 2, 3, 4]
You can of course directly go from that into whatever you want to do, like python's list comprehensions e.g. [i**2 for i in range(5)]:
> Array.from(Array(5), (_,i)=> i**2)
[0, 1, 4, 9, 16]
... or if you want to get more complicated...:
> Array.from(Array(5), (_,i)=> {
const R = /*some computation*/;
return /*etc*/;
});
[edit May,2021]: theoretically tersest way of defining such a function nowadays is f=i=>i?[...f(i-1),i]:[], where you replace f with range1 or whatever the name is, but which would be very slow (quadratic complexity) due to intermediate structures so should never be used. f=i=>i?f(i-1)&&x.push(i)&&x:x=[] is linear complexity but relies on abuse of notation and is unreadable and pollutes global variables as well. But, since defining arrow functions (which don't bind but rather inherit this) is pretty terse nowadays, you could just wrap the above solution:
const range1 = n=> Array.from(Array(n), (_,i)=> i+i);
// range1(5)==[1, 2, 3, 4, 5]
Circumstantially, the tersest way to do a range(N), if you already have a list lying around of exactly that length N, is just to map it: e.g. rather than do Array.from(Array(myArr.length), (_,i)=> i**2), you would just do myArr.map((_,i)=> i**2). (This has no side-effect unless you want it to.)
everything below is historical:
After thinking about it a bit, this is the shortest implementation of the standard range(N) function in JavaScript I could come up with:
function range1(i){return i?range1(i-1).concat(i):[]}
Note: Do not use this in production; it's O(N^2)
Contrast with current top-voted answer:
function range1(i){var x=[];var i=1;while(x.push(i++)<i){};return x}
Example:
> range1(5)
[1, 2, 3, 4, 5]
This is like the poster child for recursion, though I was expecting it to be longer until I thought of ternary-if-statement, which brings it down to 42 necessary characters.
Note that the "standard" range function returning [start,end) can be written by doing .concat(i-1).
Update: Ooh, I discovered an incredibly short version with ugly imperative syntax by abusing for loops, reverse-ordering, the fact that assignments return a value: for(y=[],i=20;y[--i]=i;){} consisting of only 25 characters (though you will want var y which you can insert into a for loop, and +1 if you don't want 0...19). While it is not shorter if you need to define a function, it is shorter than i?r(i-1).concat(i):[] if you do not need to make a function.
Added some performance profiling testcases: it seems that everything besides a standard in-order for-loop is 10x slower, at least on V8. https://jsperf.com/array-range-in-javascript
(Of course, none of this matters if you're programming in a functional style anyway and would hit every element with a function call anyway.)
It can be done with features from the ES6, currently only supported by Firefox thou. I found a compatibility table here: http://kangax.github.io/compat-table/es6/
Array.from(new Array(20), (x,i) => i+1)
If you want to have some other range then I guess you could do
Array.from(new Array(5), (x,i) => i+5)
Which would then be [5,6,7,8,9]
You can do this with a while loop where the push happens inside the condition.Array.push returns the length of the array, which happens to be the same as the value in this case. So, you can do the following:
x = []; //normally would use var here
i = 1; //normally would use var here
while(x.push(i++)<20){}
//at this point, x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
Condensed version (31 characters)
x=[];i=1;while(x.push(i++)<20);
jsFiddle example
while-- is the way to go
var a=[],b=10;while(b--)a[b]=b+1
returns [1,2,3,4,5,6,7,8,9,10]
explained with start & length
var array=[],length=20,start=5;while(length--)array[length]=length+start
returns [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]
want range?
explained with start & end
var array=[],end=30,start=25,a=end-start+1;while(a--)array[a]=end--
returns [25, 26, 27, 28, 29, 30]
for --
for(var a=[],b=20;b>0;b--,a[b]=b+1)
for++
for(var a=[],b=0;b<20;b++,a[b]=b+1)
WHY is this theway to go?
while -- is prolly the fastest loop;
direct setting is faster than push & concat;
[] is also faster than new Array(10);
it's not much longer code than all the others
byte saving techniques:
use the arguments as a placholder forthe in function variables
don't use new Array(),push(),concat() if not needed
place "(){};," only when needed.
use a,b,c,d... in short functions.
so if u want a function for this
with start,end (range)
function range(a,b,c,d){d=[];c=b-a+1;while(c--)d[c]=b--;return d}
so now range(3,7) returns [3,4,5,6,7]
u save bytes in many ways here and this function is also very fast as it does not use concat, push, new Array and it's made with a while --
If you're OK with 0-20, here are my latest favs from recent code golfing:
[...'0'.repeat(21)].map((_,i)=>i)
Array.from({length:21},(_,i)=>i)
Array(21).fill().map((_,i)=>i)
[...Array(21)].map((_,i)=>i)
Array(21).map((_,i)=>i)
[...Array(21).keys()]
Using ES6
numArr = Array(5).fill(0).reduce(arr=>{ arr.push(arr.length); return arr },[])
if you accept to have a counter starting from 0 instead of 1...
const zeroNineteen = [...Array(20).keys()];
// outputs [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19]
if you really need it to start with 1:
const terserst = [...Array(21).keys()].slice(1);
it's 30 characters and yet readable, don't you think?
I can't think of a way with less characters than ~46:
var a=[];while(a.length<20)a.push(a.length+1);
Granted, you could make a function out of that.
Reading your comments about a function, you could do something like
var range = function (start, end) {
var arr = [];
while (start <= end) {
arr.push(start++)
}
return arr;
};
Then range(1, 20) would return the array as expected.
I suppose this is the shortest way:
var i=0, arr = [];
while (i++<20){
arr.push(i);
}
or associating on the 'perverse' code in EndangeredMassa's answer:
var i,arr; while (i=i||1, (arr=arr||[]).push(i++)<20){}
You could always create a function...
function createNumArray(a, b) {
var arr = [],
i = a;
while((arr[arr.length] = i) < b) {i++}
return arr;
}
Which allows you to write succinct code later on such as...
var arr = createNumArray(1, 20);
If you are looking to shave characters off anyway possible without regard for readability, this is the best I can do:
var x=[],i=0
while(i<20)
x[i]=i+++1
Not a lot better than yours though.
Edit:
Actually this works better and shaves off a couple characters:
var x=[],i=0
while(i<20)
x[i]=++i
Edit 2:
And here's my entry for a general "range" function in the least number of characters:
function range(s,e){var x=[];while(s<e+1)x.push(s++);return x}
Again, don't write code this way. :)
Array.from({length: n}).map((_, i) => i);
In my knowledge, the option of using for loop, as you mentioned, is the most tersest.
That is,
var x = [];
for (var i=1;i<=20;i++) {
x.push(i);
}
var i = 0;
var x = [];
while (i++ < 20) x.push(i);
JSFiddle
I'd extend Array's prototype to make it simple to access:
Array.prototype.range = function(start, end) {
if (!this.length) {
while (end >= start) {
this.push(start++);
}
} else {
throw "You can only call 'range' on an empty array";
}
return this;
};
var array = [].range(1, 20);
While the above is the nearest I can think of with respect to the syntactic sugar you're looking for, you may want to try out CoffeeScript.
It supports the notation you're after.
CoffeeScript:
test = [1..20]
alert test
Renders to JavaScript:
var test;
test = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
alert(test);
You can try out live examples on their site, and see the conversion it does as you type.
Just click the TRY COFFEESCRIPT link at the top, and you'll get a console where you can test some code.
There's always the IterableInt:
for (const z of new IterableInt(15)) {
// 15,14,13....3,2,1
}
implemented like so:
class IterableInt {
constructor(val) {
if (val < 0) {
throw new Error('cannot iterate over a negative number.')
}
this.val = val;
}
static create(val){
return new IterableInt(val);
}
[Symbol.iterator]() {
const self = this;
return {
next() {
const value = self.val--;
const done = value <= 0;
return {value, done}
}
}
}
}
to do things like:
for (const z of new IterableInt(3,15)) {
// 3,4,5...14,15
}
go to this gist:
https://gist.github.com/ORESoftware/1aca4ae704b355c45702d11c0e245776