Create list/array from a dictionary using custom function - javascript

I've such an input array that every element of the array is a dictionary {x:a_int, y:a_int}. Now I need to extract all y values and create a new array, so that it can be used to calculate the maximum of all y-values. Here is my current code:
var inputArray = [{x:1,y:100},{x:2,y:101},{x:3,y:103}];
function extractY(data) {
var result = [];
data.forEach(function (item) {
result.push(item.y);
});
return result;
}
// Test code
var yArray = extractY(inputArray);
console.log(Math.max.apply(Math, yArray));
I want to make code shorter. As I'm new to javascript, I'd like to know, if it possible to shorten the function extractY(). My imagination is to have a transformation function. The code should not rely on jQuery and does not have to consider old browser compatibility.

You can simply use Array.prototype.map, which will create a new Array with the values returned by the function passed to it, like this
function extractY(data) {
return data.map(function (item) {
return item.y;
});
}
Or you can simply write the same as
console.log(Math.max.apply(Math, inputArray.map(function(item) {
return item.y;
})));

Using reduce, you can get the maximum y value directly:
inputArray.reduce(function(prev, curr) {
return prev.y > curr.y ? prev : curr;
}).y

With underscore:
_.max(_.pick(inputArray, 'y'))
With d3:
d3.max(inputArray, function(d) { return d.y; })
Note in response to #AmitJoki's comment: Yes, I know this question was not tagged underscore. If you don't want to use underscore, feel free to ignore this answer. Having said that, underscore is a highly useful utility toolbelt that is perfect for solving problems such as this, among many other things. It's exhaustively tested and robust and efficient and handles all the edge cases correctly. Unlike certain other bloated libraries, it's quite lightweight and is well worth learning.
I doubt if it falls within the realm of common sense to imply that the failure to mark a question "underscore" means that underscore-based answers are somehow not acceptable, considering that it's easy to imagine that in many cases the OP may not even be aware of that option and might welcome a suggestion about how to write more compact code, while learning a useful tool in the process.

Related

What is the benefit of using compose?

I'm learning to use Ramda and have come across compose. But I can't grasp the purpose of it
let value = R.compose( calledThird, calledSecond, calledFirst('hello') );
// vs
let value = calledThird( calledSecond( calledFirst('hello') ) );
Is it purely to allow currying? Perhaps...
let curried = R.compose( calledThird, calledSecond, calledFirst );
curried('hello');
Is there any other purpose?
Your second example is exactly the reason for it, although this in fact has nothing to do with currying.
Functional composition allows you to build more sophisticated functions out of simpler ones.
Imagine you have some datatype that you need to sort, let's say a collection of appointments. Given that you already have a sortByDate function and a reverse function, you can write sortByDateDescending as
var sortByDateDescending = function(appointments) {
return reverse(sortByDate(appointments));
}
or in ES6:
const sortByDateDescending = appointments => reverse(sortByDate(appointments));
There is nothing wrong with this. But if you were to write it with a compose helper, it has several advantages:
var sortByDateDescending = compose(reverse, sortByDate);
First of all, it's clearly shorter, and the difference will grow more substantial as you add more functions, especially with pre-es6 code.
But more importantly, this allows you to focus on what's meaningful. You are combining functions here; the data that will eventually be passed through is the goal, but while you're building the new function, it's mostly a distraction.
By writing it this way, you get to focus on what's going on: you are sorting the list by date, and then you are reversing the result.
Languages more closely focused on functional programming make this simpler still, with an unobtrusive operator rather than a function like compose. In Haskell, the equivalent would look like
sortByDateDescending = reverse . sortByDate
But Javascript does not offer that elegance. The best we can do is create functions like compose (or its order-reversed twin, pipe.)
My introduction to Ramda post offers many more examples of working in this style.
Currying, by the way, is a different beast altogether. It is one technique that makes it much easier to reuse functions in such compositions. But it's mostly a distraction here. If you're interested, I also have a post on the issue.
Scott's answer is great - just wanted to add some more real-life examples.
You can identify places to improve code when you see a lot of this sort of pattern, where you're constantly massaging some data with passthrough functions:
var list = [3, 4, 1, 2];
list = filterOutEvens(list);
list = sort(list);
list = prependFoo(list);
You may be tempted to do something like this instead:
[3, 4, 1, 2].filterOutEvens().sort().prependFoo();
But then you remember that to make that possible, you'd have to add stuff to Array.prototype, which is definitely a no-no.
R.compose gives you the next best thing (remember that it works right-to-left):
var processList = R.compose(prependFoo, sort, filterOutEvens);
processList([3, 4, 1, 2]);
Here's the full example if you want to play around with it:
function filterOutEvens(list) {
return list.filter(function(item) {
return item % 2 !== 0;
});
}
function sort(list) {
// More cleanly use R.sort here instead of native Array.prototype.sort, which operates in-place.
var diff = function(a, b) { return a - b; };
return R.sort(diff, list);
}
function prependFoo(list) {
return list.map(function(item) {
return 'foo-' + item;
});
}
var processList = R.compose(prependFoo, sort, filterOutEvens);
var result = processList([3, 4, 1, 2]);
// -> ["foo-1", "foo-3"]
// Display Stackoverflow snippet output.
document.body.innerHTML = JSON.stringify(result, null, 2);
<script src="//cdn.jsdelivr.net/ramda/0.19.1/ramda.min.js"></script>

JavaScript: shorthand for conditionally adding something to an array

I am writing a Mocha test for a server at work.
I get two potential phone numbers for a customer, at least one of which will be defined.
var homePhone = result.homePhone;
var altPhone = result.altPhone;
I want to use underscore's _.sample function to pick one of these at random. However, one of them may be undefined.
So what I was thinking was something like:
//pseudocode
var phone = _.sample([homephone || (doNothing), altphone || (doNothing)]);
the _.sample function looks like this:
http://underscorejs.org/#sample
the problem of course, is there is no shorthand syntax that I know of to conditionally add something to an array.
The verbose way to do what I want is:
var phoneArray = [];
if(homePhone){
phoneArray.push(homePhone);
}
if(altPhone){
phoneArray.push(homePhone);
}
var phoneSelection = _.sample(phoneArray);
is there a more elegant way to do this in JavaScript?
You could use .filter:
_.sample([homephone, altphone].filter(_.identity))
Another way would be:
_.sample([homephone, altphone]) || homephone || altphone;
Since you're already using underscore, I would suggest leveraging compact:
var phone = _.sample(_.compact([homephone, altphone]));
This is basically a shortened version of dave's answer, since compact is literally implemented as function(array) { return _.filter(array, _.identity); }.
What about:
var phone = (homephone && altphone)? _.sample([homephone, altphone]) : (homephone || altphone);
Array literals in JavaScript:
[ 1, 2, 3 ]
...are a way to statically declare which things go in which positions in an array. In other words, when you write the code, you already know where things will go.
In your scenario, the positions are only known dynamically. In other words, you don't know where they'll go until you run the program on a given set of inputs.
So basically what you're asking for is impossible, barring any radical changes to how array literals work in future versions of JS. However, if all you want is to save typing, #dave's answer is pretty nice. I'm mainly just clarifying that array literals by themselves don't have this capability.

reduce javascript code when using the map function

I want to iterate over an array and do something to each of the element
d = d.map(function(d){
return _.omit(d, 'password');
})
d = d.map(function(d){
return d.toString();
})
these functions are working correctly. But after it showed up too many times the code becomes really messy.
So I was wondering if there's easier ways to do what I want to do? I am hoping to reduce the code to one line only using bind or apply keywords or some modules (maybe lodash or underscore..). Is this possible?
If you're using a version of JavaScript that supports arrow functions, you could use those:
d = d.map((d) => _.omit(d, 'password'));
Or if you're repeating the same code a lot, you can make helper functions:
function removePasswords(d) {
return d.map(function (d) {
return _.omit(d, 'password');
});
}
d = removePasswords(d);
If you're performing a lot of maps one after the other, you can combine their contents
d = d.map(function(d) {
return _.omit(d, 'password').toString();
});
Otherwise, I don't think it's going to get much shorter than what you already have. It's already pretty short.
You may want to look into using Coffeescript if you feel that JavaScript is too verbose:
d = d.map (d) -> _.omit(d, 'password')

Best way to do a non-mutating inverse tail in javascript using Underscore/Lodash

I'm an avid user of lodash/underscore in my node.js projects, and I find myself in a situation where I need to recursively iterate through an array from right to left in a manner similar to the below code (assuming that all calls are synchronous):
function makeDir(pathArray) {
var unsulliedPath = clone(pathArray);
var lastGuy = pathArray.pop();
var restOfEm = pathArray;
if dirExists(unsulliedPath) {
console.log("Your job is done!");
} else {
makeDir(restOfEm);
makeDir(unsulliedPath);
}
}
Having to clone and mutate the pathArray argument bugs me, however. So I could do this:
function makeDir(pathArray) {
var lastGuy = _.last(pathArray);
// EITHER I could...
var restOfEm = _(pathArray).reverse().tail().reverse().value();
// OR I could do...
var restOfEm = _.first(pathArray, pathArray.length - 1);
if dirExists(pathArray) {
console.log("Your job is done!");
} else {
makeDir(restOfEm);
makeDir(pathArray);
}
}
Okay, that takes care of having to clone the argument passed in. That underscore incantation is slightly ugly, though.
Do lodash/underscore contain a simpler and clearer method for getting the inverse of _.rest(), that is, every element except the last? If not, is there a preferred idiomatic solution for implementing this method in Javascript for use alongside lodash/underscore-style functional libraries, or is this simply nit-picking?
Thanks in advance, and apologies for any glaring omissions or errors in my question.
Why bother with underscore/lodash.
var last = pathArray.slice(-1)[0];
var rest = pathArray.slice(0, -1);
slice will do this all for you very easily...
Use Array.splice https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice and if you do not want to modify the original, do Array.slice to copy the original and then Array.splice.
ie:
var rest = pathArray.slice(0);
var last = rest.splice(-1, 1)[0];

Programming optional ignorance

In Javascript what is the best way to handle scenarios when you have a set of arrays to perform tasks on sets of data and sometimes you do not want to include all of the arrays but instead a combination.
My arrays are labeled in this small snippet L,C,H,V,B,A,S and to put things into perspective the code is around 2500 lines like this. (I have removed code notes from this post)
if(C[0].length>0){
L=L[1].concat(+(MIN.apply(this,L[0])).toFixed(7));
C=C[1].concat(C[0][0]);
H=H[1].concat(+(MAX.apply(this,H[0])).toFixed(7));
V=V[1].concat((V[0].reduce(function(a,b){return a+b}))/(V[0].length));
B=B[1].concat((MAX.apply(this,B[0])-MIN.apply(this,B[0]))/2);
A=A[1].concat((MAX.apply(this,A[0])-MIN.apply(this,A[0]))/2);
D=D[1].concat((D[0].reduce(function(a,b){return a+b}))/(D[0].length));
S=S[1].concat((S[0].reduce(function(a,b){return a+b}))/(S[0].length));
}
It would seem counter-productive in this case to litter the code with tones of bool conditions asking on each loop or code section if an array was included in the task and even more silly to ask inside each loop iteration with say an inline condition as these would also slow down the processing and also make the code look like a maze or rabbit hole.
Is there a logical method / library to ignore instruction or skip if an option was set to false
All I have come up with so far is kind of pointless inline thing
var op=[0,1,1,0,0,0,0,0]; //options
var L=[],C=[],H=[],V=[],B=[],A=[],D=[],S=[];
op[0]&&[L[0]=1];
op[1]&&[C[0]=1,console.log('test, do more than one thing')];
op[2]&&[H[0]=1];
op[3]&&[V[0]=1];
op[4]&&[B[0]=1];
op[5]&&[A[0]=1];
op[6]&&[A[0]=1];
It works in that it sets only C[0] and H[0] to 1 as the options require, but it fails as it needs to ask seven questions per iteration of a loop as it may be done inside a loop. Rather than make seven versions of the the loop or code section, and rather than asking questions inside each loop is there another style / method?
I have also noticed that if I create an array then at some point make it equal to NaN rather than undefined or null the console does not complain
var L=[],C=[],H=[],V=[],B=[],A=[],D=[],S=[];
L=NaN;
L[0]=1;
//1
console.log(L); //NaN
L=undefined;
L[0]=1
//TypeError: Cannot set property '0' of undefined
L=null
L[0]=1
//TypeError: Cannot set property '0' of null
Am I getting warmer? I would assume that if I performed some math on L[0] when isNaN(L)===true that the math is being done but not stored so the line isn't being ignored really..
If I understand what you want I would do something like this.
var op = [...],
opchoice = {
//these can return nothing, no operation, or a new value.
'true': function(val){ /*operation do if true*/ },
'false': function(val){ /*operation do if false*/ },
//add more operations here.
//keys must be strings, or transformed into strings with operation method.
operation: function(val){
//make the boolean a string key.
return this[''+(val == 'something')](val);
}
};
var endop = [];//need this to prevent infinite recursion(loop).
var val;
while(val = op.shift()){
//a queue operation.
endop.push(opchoice.operation(val));
}
I'm sure this is not exactly what you want, but it's close to fulfilling the want of not having a ton of conditions every where.
Your other option is on every line do this.
A = isNaN(A) ? A.concat(...) : A;
Personally I prefer the other method.
It looks like you repeat many of the operations. These operations should be functions so at least you do not redefine the same function over and over again (it is also an optimization to do so).
function get_min(x)
{
return +(MIN.apply(this, a[0])).toFixed(7);
}
function get_max(x)
{
return +(MAX.apply(this, a[0])).toFixed(7);
}
function get_average(x)
{
return (x[0].reduce(function(a, b) {return a + b})) / (x[0].length);
}
function get_mean(x)
{
return (MAX.apply(this, x[0]) - MIN.apply(this, x[0])) / 2;
}
if(C[0].length > 0)
{
L = L[1].concat(get_min(L));
C = C[1].concat(C[0][0]);
H = H[1].concat(get_max(H));
V = V[1].concat(get_average(V));
B = B[1].concat(get_mean(B));
A = A[1].concat(get_mean(A);
D = D[1].concat(get_average(D));
S = S[1].concat(get_average(S));
}
You could also define an object with prototype functions, but it is not clear whether it would be useful (outside of putting those functions in a namespace).
In regard to the idea/concept of having a test, what you've found is probably the best way in JavaScript.
op[0] && S = S[1].concat(get_average(S));
And if you want to apply multiple operators when op[0] is true, use parenthesis and commas:
op[3] && (V = V[1].concat(get_average(V)),
B = B[1].concat(get_mean(B)),
A = A[1].concat(get_mean(A));
op[0] && (D = D[1].concat(get_average(D)),
S = S[1].concat(get_average(S)));
However, this is not any clearer, to a programmer, than an if() block as shown in your question. (Actually, many programmers may have to read it 2 or 3 times before getting it.)
Yet, there is another solution which is to use another function layer. In that last example, you would do something like this:
function VBA()
{
V = V[1].concat(get_average(V));
B = B[1].concat(get_mean(B));
A = A[1].concat(get_mean(A));
}
function DS()
{
D = D[1].concat(get_average(D));
S = S[1].concat(get_average(S));
}
op = [DS,null,null,VBA,null,null,...];
for(key in op)
{
// optional: if(op[key].hasOwnProperty(key)) ... -- verify that we defined that key
if(op[key])
{
op[key](); // call function
}
}
So in other words you have an array of functions and can use a for() loop to go through the various items and if defined, call the function.
All of that will very much depend on the number of combinations you have. You mentioned 2,500 lines of code, but the number of permutations may be such that writing it one way or the other will possibly not reduce the total number of lines, but it will make it easier to maintain because many lines are moved to much smaller code snippet making the overall program easier to understand.
P.S. To make it easier to read and debug later, I strongly suggest you put more spaces everywhere, as shown above. If you want to save space, use a compressor (minimizer), Google or Yahoo! both have one that do a really good job. No need to write your code pre-compressed.

Categories

Resources