Can a function return two values?
Can a function return two values? { I came across this in C} Any possibility of something in JavaScript
You can't return two distinct values but you can return an object or array. This is perfectly valid, as long as you document the behavior for anyone else who might encounter the code. It's helpful if the two returned values are truly related. If not, it can become difficult to understand the function. And just returning a diverse array of values from an object would be considered a bad practice by many people since a function's purpose is usually to perform a discrete action which may return a discrete value.
// As an object
function() {
return {val1: "value 1", val2: "value 2"};
}
// As an array
function() {
return ["value 1", "value 2"];
}
Not directly, but no one can stop you from returning an Array with multiple elements:
function modify(a,b) {
return [a*2, b*2];
}
var res = multiple(5, 10);
console.log( res );
To push this a little further, we could use such a "mapped" result to call another method. Javascripts .apply() comes in pretty handy for this.
function add(v1, v2) {
return v1 + v2;
}
and we could call
add.apply( null, modify(2,4) );
this effectively would be like
add(4, 8) // === 12
Related
Languages such as Python and Java have special methods for sorting custom classes. In JavaScript, toString() can be overridden, but this does not work easily for numeric values.
As a workaround, I added a method called compareTo() to the class, although this still requires a function to call it.
class NumericSortable {
constructor(newVal) {
this.val = newVal
}
compareTo(other) {
return this.val - other.val
}
}
const objectList = [
new NumericSortable(3),
new NumericSortable(1),
new NumericSortable(20),
]
objectList.sort(
function(a, b) { return a.compareTo(b) })
console.log(objectList)
Is there a way to modify the class so it can be sorted without requiring a function to be defined inside sort()?
Perhaps there is a good way to override toString() that will work for numeric values. However, solutions such as localeCompare() or a collator require two arguments, and they would not be passed to the overridden toString() method at the same time.
You can add a static method to your NumericSortable class, and pass that into the sort call. This idea can be extended to any custom class that need to define how two instances are to be compared for sorting.
class NumericSortable {
constructor(value) {
this.value = value;
}
static compare(a,b) {
return a.value - b.value;
}
}
const arr = [
new NumericSortable(3),
new NumericSortable(1),
new NumericSortable(20),
];
arr.sort(NumericSortable.compare);
console.log(arr);
This makes things more explicit, and easier for anyone else reading the code to reason about how the array is being sorted.
I like to make a function that returns a sort function for these cases.
function by(prop){
return function(a,b){return a[prop]-b[prop];};
}
this let's you specify the object's to-be-sorted property at call-time, letting one generic function do a lot of heavy lifting.
objectList.sort(by("val"))
This avoids the need for a custom callback each sort, though with fat arrows that's not the burden it used to be anyway...
If no comparator is provided, each time two items in the array are compared, they'll be coerced to strings, and then those strings will be compared lexiographically to determine which object will come before the other in the sorted array. So, if you don't want to pass a comparator, adding a toString method to implement the desired sorting logic is the only other approach.
Unfortunately, for your situation, lexiographic comparison alone based on the .vals won't cut it; 1 will come before 20, and 20 will come before 3. If the numbers involved won't get so high as to have es in their string version, you could .padStart the returned string so that each compared numeric string will have the same number of characters (thereby allowing lexiographic comparison to work).
class NumericSortable {
constructor(newVal) {
this.val = newVal
}
// Unused now
compareTo(other) {
return this.val - other.val
}
toString() {
return String(this.val).padStart(15, '0');
}
}
const objectList = [
new NumericSortable(3),
new NumericSortable(1),
new NumericSortable(20),
]
objectList.sort()
console.log(objectList)
You may wish to account for negative numbers too.
Still, this whole approach is a bit smelly. When possible, I'd prefer a comparator instead of having to fiddle with the strings to get them to compare properly.
From my above comment ...
"The OP needs to wrap the build-in sort method into an own/custom implementation of Array.prototype.sort. But why should one do it? Just for the sake of not writing a comparing sort-callback?"
Having said the above, I herby nevertheless provide an implementation of the above mentioned approach just in order to prove to the OP that it's manageable (after all it is exactly what the OP did ask for), but also to show to the audience that the effort (even though it's a one time effort) of doing so is much greater than other already provided suggestions / solutions.
class NumericSortable {
constructor(newVal) {
this.val = newVal;
}
compareTo(other) {
return this.val - other.val;
}
}
const objectList = [
new NumericSortable(3),
new NumericSortable(1),
new NumericSortable(20),
];
objectList
// - sorting by overwritten custom `sort` function with
// an already build-in `compareTo` based custom compare
// function and no additionally passed compare function.
.sort();
console.log({ objectList });
objectList
// - reverse sorting by overwritten custom `sort` function
// with an additionally passed compare function.
.sort((a, b) => (-1 * a.compareTo(b)));
console.log({ objectList });
console.log(
'... simple sort-implementation defaul-test ...\n[1,4,9,0,6,3].sort() ...',
[1,4,9,0,6,3].sort()
);
console.log(
'... simple sort-implementation defaul-test ...\n["foo", "biz", "baz", "bar"].sort() ...',
["foo", "biz", "baz", "bar"].sort()
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
<script>
(function (arrProto) {
// save the native `sort` reference.
const coreApiSort = arrProto.sort;
// type detection helper.
function isFunction(value) {
return (
'function' === typeof value &&
'function' === typeof value.call &&
'function' === typeof value.apply
);
}
// different comparison helper functionality.
function defaultCompare(a, b) {
return (a < b && -1) || (a > b && 1) || 0;
}
function localeCompare(a, b) {
return a?.localeCompare?.(b) ?? defaultCompare(a, b);
}
function customDefaultCompare(a, b) {
const isCustomComparableA = isFunction(a.compareTo);
const isCustomComparableB = isFunction(b.compareTo);
return (isCustomComparableA && isCustomComparableB)
? a.compareTo(b)
: localeCompare(a, b);
}
// the new `sort` functionality.
function customSort(customCompare) {
return coreApiSort
// - (kind of "super") delegation to the
// before saved native `sort` reference ...
.call(this, (
// ... by using a cascade of different
// comparison functionality.
isFunction(customCompare)
&& customCompare
|| customDefaultCompare
));
}
Object
// - overwrite the Array prototype's native `sort`
// method with the newly implemented custom `sort`.
.defineProperty(arrProto, 'sort', {
value: customSort,
});
}(Array.prototype));
</script>
I went over this function over and over in Chrome debugger and still can't understand what return a does. Thanks for helping me out!
Here's some clarification:
I understand the first round. The anonymous function gets called with the following parameters:
active = "", rest = "abc", a = []
It then calls itself til rest is empty, when it populates the a array:
active = "abc", rest = "", a = ["abc"]
At this point we arrive to return a, and the debugger jumps to the second fn call in the else statement instead of the first if statement. The parameters already look like this:
active = "ab", rest = "c", a = ["abc"]
This is the part I don't understand at all. I know the recursion is only over when active and rest is empty, but after return a the if statements don't even get checked in the debugger, it just highlights the mentioned second function call, and at that point "c" is already assigned to rest. I guess the reason why this function doesn't produce duplicates also lies here, but that might be another question if not. Anyway, thanks again for the help!
combinations("abc");
function combinations(str) {
var fn = function(active, rest, a) {
if (!active && !rest)
return;
if (!rest) {
a.push(active);
} else {
fn(active + rest[0], rest.slice(1), a);
fn(active, rest.slice(1), a);
}
return a;
}
return fn("", str, []);
}
In this case the recursion construct is written oddly and the "return a" is merely to smuggle out the mutated array, the same object initially supplied, back to the helper function so that a direct return can be used on the inner recursive function call. (In most contexts, and especially those discussed in recursion primers, recursive functions usually utilize the returned value.)
Here is a cleaner re-write using the helper function more. I also removed all explicit return statements because they were not adding value here.
function combinations(str) {
var fn = function(active, rest, a) {
if (!active && !rest) {
// base case #1 - implicit return, no recursive call
} else if (!rest) {
// base case #2 - implicit return, no recursive call
a.push(active);
} else {
// recursive case, where function is called again
// (the object "a" is modified in recursion;
// result of recursion not directly used)
fn(active + rest[0], rest.slice(1), a);
fn(active, rest.slice(1), a);
}
}
var o = []; // only one output object created..
fn("", str, o); // ..mutated..
return o; // ..and returned to caller.
}
It should then be easy to observe that passing "a" to the recursive function is not needed (ie. it could access "o" in the enclosing scope) because there is no new object assigned to "a" after the initial result array is created.
There is a subtle difference in the re-write will (more correctly) return an empty array for an empty input string.
While I understand that this question is primarily about how that particular recursive implementation works (and there's already an excellent answer to that!), I think it's worth pointing out that it's an odd implementation, and something like this is probably cleaner:
const combinations = (str, active = '') =>
str .length == 0
? active .length == 0
? []
: [active]
: [
... combinations (str .slice (1), active + str [0]),
... combinations (str .slice (1), active)
]
console .log (combinations ('abc'))
I am learning functional programming in Javascript and using Ramda. I have this object
var fieldvalues = { name: "hello there", mobile: "1234",
meta: {status: "new"},
comments: [ {user: "john", comment: "hi"},
{user:"ram", comment: "hello"}]
};
to be converted like this:
{
comments.0.comment: "hi",
comments.0.user: "john",
comments.1.comment: "hello",
comments.1.user: "ram",
meta.status: "new",
mobile: "1234",
name: "hello there"
}
I have tried this Ramda source, which works.
var _toDotted = function(acc, obj) {
var key = obj[0], val = obj[1];
if(typeof(val) != "object") { // Matching name, mobile etc
acc[key] = val;
return acc;
}
if(!Array.isArray(val)) { // Matching meta
for(var k in val)
acc[key + "." + k] = val[k];
return acc;
}
// Matching comments
for(var idx in val) {
for(var k2 in val[idx]) {
acc[key + "." + idx + "." + k2] = val[idx][k2];
}
}
return acc;
};
// var toDotted = R.pipe(R.toPairs, R.reduce(_toDotted, {}));
var toDotted = R.pipe(R.toPairs, R.curry( function(obj) {
return R.reduce(_toDotted, {}, obj);
}));
console.log(toDotted(fieldvalues));
However, I am not sure if this is close to Functional programming methods. It just seems to be wrapped around some functional code.
Any ideas or pointers, where I can make this more functional way of writing this code.
The code snippet available here.
UPDATE 1
Updated the code to solve a problem, where the old data was getting tagged along.
Thanks
A functional approach would
use recursion to deal with arbitrarily shaped data
use multiple tiny functions as building blocks
use pattern matching on the data to choose the computation on a case-by-case basis
Whether you pass through a mutable object as an accumulator (for performance) or copy properties around (for purity) doesn't really matter, as long as the end result (on your public API) is immutable. Actually there's a nice third way that you already used: association lists (key-value pairs), which will simplify dealing with the object structure in Ramda.
const primitive = (keys, val) => [R.pair(keys.join("."), val)];
const array = (keys, arr) => R.addIndex(R.chain)((v, i) => dot(R.append(keys, i), v), arr);
const object = (keys, obj) => R.chain(([v, k]) => dot(R.append(keys, k), v), R.toPairs(obj));
const dot = (keys, val) =>
(Object(val) !== val
? primitive
: Array.isArray(val)
? array
: object
)(keys, val);
const toDotted = x => R.fromPairs(dot([], x))
Alternatively to concatenating the keys and passing them as arguments, you can also map R.prepend(key) over the result of each dot call.
Your solution is hard-coded to have inherent knowledge of the data structure (the nested for loops). A better solution would know nothing about the input data and still give you the expected result.
Either way, this is a pretty weird problem, but I was particularly bored so I figured I'd give it a shot. I mostly find this a completely pointless exercise because I cannot picture a scenario where the expected output could ever be better than the input.
This isn't a Rambda solution because there's no reason for it to be. You should understand the solution as a simple recursive procedure. If you can understand it, converting it to a sugary Rambda solution is trivial.
// determine if input is object
const isObject = x=> Object(x) === x
// flatten object
const oflatten = (data) => {
let loop = (namespace, acc, data) => {
if (Array.isArray(data))
data.forEach((v,k)=>
loop(namespace.concat([k]), acc, v))
else if (isObject(data))
Object.keys(data).forEach(k=>
loop(namespace.concat([k]), acc, data[k]))
else
Object.assign(acc, {[namespace.join('.')]: data})
return acc
}
return loop([], {}, data)
}
// example data
var fieldvalues = {
name: "hello there",
mobile: "1234",
meta: {status: "new"},
comments: [
{user: "john", comment: "hi"},
{user: "ram", comment: "hello"}
]
}
// show me the money ...
console.log(oflatten(fieldvalues))
Total function
oflatten is reasonably robust and will work on any input. Even when the input is an array, a primitive value, or undefined. You can be certain you will always get an object as output.
// array input example
console.log(oflatten(['a', 'b', 'c']))
// {
// "0": "a",
// "1": "b",
// "2": "c"
// }
// primitive value example
console.log(oflatten(5))
// {
// "": 5
// }
// undefined example
console.log(oflatten())
// {
// "": undefined
// }
How it works …
It takes an input of any kind, then …
It starts the loop with two state variables: namespace and acc . acc is your return value and is always initialized with an empty object {}. And namespace keeps track of the nesting keys and is always initialized with an empty array, []
notice I don't use a String to namespace the key because a root namespace of '' prepended to any key will always be .somekey. That is not the case when you use a root namespace of [].
Using the same example, [].concat(['somekey']).join('.') will give you the proper key, 'somekey'.
Similarly, ['meta'].concat(['status']).join('.') will give you 'meta.status'. See? Using an array for the key computation will make this a lot easier.
The loop has a third parameter, data, the current value we are processing. The first loop iteration will always be the original input
We do a simple case analysis on data's type. This is necessary because JavaScript doesn't have pattern matching. Just because were using a if/else doesn't mean it's not functional paradigm.
If data is an Array, we want to iterate through the array, and recursively call loop on each of the child values. We pass along the value's key as namespace.concat([k]) which will become the new namespace for the nested call. Notice, that nothing gets assigned to acc at this point. We only want to assign to acc when we have reached a value and until then, we're just building up the namespace.
If the data is an Object, we iterate through it just like we did with an Array. There's a separate case analysis for this because the looping syntax for objects is slightly different than arrays. Otherwise, it's doing the exact same thing.
If the data is neither an Array or an Object, we've reached a value. At this point we can assign the data value to the acc using the built up namespace as the key. Because we're done building the namespace for this key, all we have to do compute the final key is namespace.join('.') and everything works out.
The resulting object will always have as many pairs as values that were found in the original object.
I'm trying to use groupBy with RxJs, and I need to use objects as keys. If I don't and I use, for example, simple strings like this:
var types = stream.groupBy(
function (e) { return e.x; }); //x is a string
then everything goes fine and my subscription is called once, and once only, for each different key. But if I try with objects, the subscription is called for each element from stream, even if a key happens to be the same as previous ones.
There is of course a problem about object equality, but this is where I get confused because I don't understant how to use the additional arguments for groupBy. The latest version of docs says there have a 3rd argument that can be a comparer, but it never gets called. Earlier docs talk about a key serializer which is a totally different idea, but neither ways work for me.
Looking at Rx source code, I see attempts to check for a getHashCode function, but I do not find and documentation about it. Code like this:
var types = stream.groupBy(
function (e) {
return { x: e.x, y: e.y }; //is this valid at all?
},
function (e) { return e; },
function (...) { return ???; }); //what am I supposed to do here?
is what i'm trying to write, but no luck, and whatever I put for the 3rd callback is not called.
What's wrong here?
The simplest solution is to make sure your key function returns a number or string. But if you really want to return an object as your key, then you can use comparer and hashCode to help groupBy. Instead of hashCode (which requires you return a number), you can use valueOf which lets you return a string.
hashCode and valueOf should work similar to the c# Object.GetHashCode.
They should return a value such that:
Two keys that are considered equal should return the same value every time.
Two keys that are considered not equal should usually return a different value (to minimize collisions). The better you can ensure this, the more efficient the dictionary will be.
The difference is hashCode should return a number and valueOf can return a number or a string. Thus valueOf is easier to implement.
The rules for the comparer is that it takes 2 key values and should return true to indicate equality and false to indicate inequality.
So, you might write your example as:
var valueOf = function () {
return JSON.stringify(this);
};
var keyCompare = function (a, b) { return a.x === b.x && a.y === b.y; };
var types = stream.groupBy(
function (e) {
return { x: e.x, y: e.y, valueOf: valueOf }; //is this valid at all?
},
function (e) { return e; },
keyCompare);
But if your valueOf function is actually producing unique values that match your comparer and you don't really care about whether the key is tramsitted downstream as an actual object, then just make your life easier and transform your key into a string and use a string key like so:
var types = stream.groupBy(
function (e) { return JSON.stringify({ x: e.x, y: e.y }); },
function (e) { return e; });
this.String = {
Get : function (val) {
return function() {
return val;
}
}
};
What is the ':' doing?
this.String = {} specifies an object. Get is a property of that object. In javascript, object properties and their values are separated by a colon ':'.
So, per the example, you would call the function like this
this.String.Get('some string');
More examples:
var foo = {
bar : 'foobar',
other : {
a : 'wowza'
}
}
alert(foo.bar); //alerts 'foobar'
alert(foo.other.a) //alerts 'wowza'
Others have already explained what this code does. It creates an object (called this.String) that contains a single function (called Get). I'd like to explain when you could use this function.
This function can be useful in cases where you need a higher order function (that is a function that expects another function as its argument).
Say you have a function that does something to each element of an Array, lets call it map. You could use this function like so:
function inc (x)
{
return x + 1;
}
var arr = [1, 2, 3];
var newArr = arr.map(inc);
What the map function will do, is create a new array containing the values [2, 3, 4]. It will do this by calling the function inc with each element of the array.
Now, if you use this method a lot, you might continuously be calling map with all sorts of arguments:
arr.map(inc); // to increase each element
arr.map(even); // to create a list of booleans (even or odd)
arr.map(toString); // to create a list of strings
If for some reason you'd want to replace the entire array with the same string (but keeping the array of the same size), you could call it like so:
arr.map(this.String.Get("my String"));
This will create a new array of the same size as arr, but just containing the string "my String" over and over again.
Note that in some languages, this function is predefined and called const or constant (since it will always return the same value, each time you call it, no matter what its arguments are).
Now, if you think that this example isn't very useful, I would agree with you. But there are cases, when programming with higher order functions, when this technique is used.
For example, it can be useful if you have a tree you want to 'clear' of its values but keep the structure of the tree. You could do tree.map(this.String.Get("default value")) and get a whole new tree is created that has the exact same shape as the original, but none of its values.
It assigns an object that has a property "Get" to this.String. "Get" is assigned an anonymous function, which will return a function that just returns the argument that was given to the first returning function. Sounds strange, but here is how it can be used:
var ten = this.String["Get"](10)();
ten will then contain a 10. Instead, you could have written the equivalent
var ten = this.String.Get(10)();
// saving the returned function can have more use:
var generatingFunction = this.String.Get("something");
alert(generatingFunction()); // displays "something"
That is, : just assigns some value to a property.
This answer may be a bit superflous since Tom's is a good answer but just to boil it down and be complete:-
this.String = {};
Adds an object to the current object with the property name of String.
var fn = function(val) {
return function() { return(val); }
}
Returns a function from a closure which in turn returns the parameter used in creating the closure. Hence:-
var fnInner = fn("Hello World!");
alert(fnInner()); // Displays Hello World!
In combination then:-
this.String = { Get: function(val) {
return function() { return(val); }
}
Adds an object to the current object with the property name of String that has a method called Get that returns a function from a closure which in turn returns the parameter used in creating the closure.
var fnInner = this.String.Get("Yasso!");
alert(fnInner()); //displays Yasso!