Is there a way to prevent errors from being thrown while filtering?
The below function sometimes fails at conversationMember.Name.toLowerCase() when there is no conversationMember.
If it helps, this is also a computed property in a Vue application.
Should you need more information, please just ask!
filteredConversations() {
var self = this;
var filteredConvos = self.conversations;
filteredConvos = filteredConvos.filter(conversation => {
return conversation.MembershipData.some(conversationMember => {
return conversationMember.Name.toLowerCase().includes(
self.conversationSearchTerm.toLowerCase()
);
});
});
return filteredConvos;
},
This doesn't seem to have anything to do with arrays.
From your code I understand conversationMember.Name is supposed to be a string (because you're calling .toLowerCase() on it), which means incudes here is not Array.prototype.includes, but String.prototype.includes, especially since self.conversationSearchTerm seems to also be a string (you're also calling .toLowerCase() on it).
So, the problem is you're using includes on something that should be a string but is not. The simple fix is to default it to an empty string when it's falsy:
return (conversationMember.Name || '').toLowerCase().includes(
(self.conversationSearchTerm || '').toLowerCase()
);
As a side note, you don't need the var self = this;. this is available inside your filter since the filter is an arrow function. So your function (I'm guessing it's a computed but it can as well be a method) could look like this:
filteredConversations() {
return this.conversations.filter(c =>
c.MembershipData.some(md =>
(md.Name || '').toLowerCase().includes(
(this.conversationSearchTerm || '').toLowerCase()
)
)
);
}
One last note: this will still fail if any of your conversations does not have a MembershipData holding an array. To get around that, you could default it to an empty array on the fly:
...
(c.MembershipData || []).some(md =>
...
As expected, any conversation without an array in MembershipData will be filtered out by the function (not included in the result) - because .some(condition) will return false when called on an empty array.
Currently learning RxJS, I'm not gonna lie, I had difficulties understanding it, especially in terms of "Why do we even want to use if we have promises"
But now I think I made small step further.
I know I should avoid nested subscriptions.
Trying to write as short as possible code to merge two streams result into single variable.
So I have two arrays simulating result of streams, which I want to join.
Fights array should became new obj array inside boxers objects
const boxers = [
{
user_id:1,
first_name:'Lennox ',
last_name:'Lewis',
nationality:"UK"
},
{
user_id:2,
first_name:'Mike',
last_name:'Tyson',
nationality:'USA'
},
{
user_id:3,
first_name:'Riddick',
last_name:'Bowe',
nationality:'USA'
},
];
const fights = [
{
fight_id:1,
user_id:1,
opponnent_id:2,
winner_id:1,
venue:'Memphis Pyramid, Tennessee'
}
]
And then I wrote code:
const boxersWithFights2 = boxersStream.pipe(
flatMap(boxers => {
return fightsStream.pipe(
flatMap(fights => {
boxers.map(boxer => boxer.fights = fights.filter(fight => fight.user_id === boxer.user_id ||fight.opponnent_id === boxer.user_id ))
return boxers;
})
)
}
));
Surprisingly this works as expected.
When I subscribe to boxersWithFights, it console.logs me with properly mapped objects.
So it probably also work when returned from external api, but then I would of course need another map() operator.
My question: Is this code written well? Can it be written to be more clean & elegant ?
I also know I could do that easier with e.g. forkJoin, but I really wanted to test flatMap(mergeMap) operator.
You shouldn't mutate data in the stream but boxer.fights = does it.
Also you can combine the streams together via forkJoin because they don't depend on each other.
Try to use map operator instead:
const boxersWithFights2 = forkJoin([boxersStream, fightsStream]).pipe(
map(([boxers, fights]) => {
return boxers.map(boxer => ({
...boxer,
fights: fights.filter(fight => fight.user_id === boxer.user_id ||fight.opponnent_id === boxer.user_id ),
})),
));
Task
I need to make an app that reads a CSV file, transforms its data and then outputs it as another CSV file.
The input has the following format:
13:25:37 up 19 days, 21:35, 4 users, load average: 0.02, 0.02, 0.00
13:25:38 up 19 days, 21:35, 4 users, load average: 0.02, 0.02, 0.00
... so on
For those of you who are UNIX fans, you will recognise this as the output from the console command uptime.
The output format I want is the following:
RowNum, Avg Load
1,0.02
2,0.02
Where the first column is the row number in the CSV and the second is the number part of load average: 0.02.
All other columns are to be ignored.
Problem
Trying to do this as functionally as I can, I decided to use ramda.
This has been ... a challenge, to say the least. Right now, my code has several structural issues, but I want to focus on the main function, which is not working. Every time I execute my code I get the error:
index.js:54
.then( () => console.log("Done!") )
^
TypeError: main(...).then is not a function
Which is confusing because in both functions I pass to R.ifElse I return a Promise.
Code
const fs = require("fs");
const csvReader = require("csvreader");
const R = require("ramda");
const isString = require("lodash.isstring");
const { promisify } = require("util");
const argv = require("minimist")(process.argv.slice(2));
const appedFileAsync = promisify( fs.appendFile );
const createProcessData = () => {
const stringifyArray = array => `${array.toString()}\n`;
const write = str => fs.appendFileSync( argv.outputFile, str );
const getAvg = R.pipe(
R.replace("load average:", ""),
R.trim
);
let elapsedTime = 1;
const transform = list => [ elapsedTime++, getAvg ( R.nth( 3, list ) ) ];
return R.pipe(
transform,
stringifyArray,
write
);
};
const printHelp = () => {
console.log(`
=== MAN HELP ===
Usage: npm start -- --inputFile input.csv --outputFile output.csv
--inputFile: location of an input file in CSV format
--outputFile: location of an output file to append the new information to.
If this file does not exist, it will be created.
`);
return Promise.resolve();
};
const execute = () => appedFileAsync( argv.outputFile, "Time, Avg Load\n" )
.then( ( ) => csvReader.read( argv.inputFile, createProcessData() ) );
const main = () => {
const isInvalidFileName = R.anyPass( [ R.isNil, R.isEmpty, R.pipe ( isString, R.not ) ] );
const hasInvalidArgs = R.either( isInvalidFileName( argv.inputFile ), isInvalidFileName( argv.outputFile ) );
return R.ifElse(
hasInvalidArgs,
printHelp,
execute
);
};
main()
.then( () => console.log("Done!") )
.catch( console.error );
Question
What is wrong with my code ?
This is how to think of ifElse:
const ifElse = (predicate, consequent, alternative) =>
(...val) => predicate(...val) ? consequent(...val) : alternative(...val);
So
const comp = ifElse(
(a, b) => a < b,
(a, b) => `${a} is smaller than ${b}`,
(a, b) => `${a} is at least as large as ${b}`
)
comp(12, 7) //=> "12 is at least as large as 7"
The main point is that the first argument to ifElse is a function. But you pass it the result of this:
R.either( isInvalidFileName( argv.inputFile ), isInvalidFileName( argv.outputFile ) )
Now normally, either returns a function. But that depends upon you supplying functions to it. The assumption is that if you don't supply functions, you know what you are doing and are supplying container types with ap and map methods, so that either is slightly more generic. But you're supplying booleans such as the result of isInvalidFileName( argv.inputFile ). At that point the behavior is not well defined. Perhaps that should be changed, but Ramda's philosophy is generally garbage-in-garbage-out. So that either call, for whatever reason, is returning [undefined].
And that means that you're supplying [undefined] as the predicate function to ifElse. You should receive an error when you try to call it. I haven't tried to trace down why that error is being shadowed by the one you see.
As to how to fix this using Ramda, I'm not really sure where to start. This is pretty far from Ramda's usual style. If nothing else, functions that accept no parameters are extremely rare in Ramda. I guess I would start the Ramda part of this with a function that accepts argv.inputFile and argv.outputFile, either as individual objects or perhaps as that single object argv.
I actually sure that there is a simple answer to that , and that I probably just don't use promises correctly but still.
Suppose I have a method that returns a promise and I have a method that needs to receive two parameters to work , one that I actually have already.
Now since I don't want my functions to be endless I split them to smaller ones , and now I just cant get hold of my parameter.
So to be clear , here is something that has not problem working ( might be a bit schematic though)
var origFeatures = [];
_.each(wrappedFeatures, function (wrappedFeature) {
bufferTasks.push(geometryEngineAsync.buffer(
[feature.geometry]
, feature.geometry.type === "polygon" ? [0] : [5]
, esriSRUnit_Meter));
}
}.bind(this));
all(bufferTasks).then(function(bufferedFeatures){
//doing something with the bufferedFeatures AND origFeatures
}.bind(this))
now Imaging the methods are long so when I split to this
defined somewhere before
function _saveGeometries(bufferedFeatures){
//do something with buffered features AND the original features
}
var origFeatures= [];
_.each(wrappedFeatures, function (wrappedFeature) {
bufferTasks.push(geometryEngineAsync.buffer(
[feature.geometry]
, feature.geometry.type === "polygon" ? [0] : [5]
, esriSRUnit_Meter));
}
}.bind(this));
all(bufferTasks)
.then(this._saveNewGeometries.bind(this))
I of course cannot see the original features because they are not in the scope of the wrapping function
So what I did try to do already is to create a a function in the middle and resolve it with the async result and the additional parameter, but the additional parameter is undefined
var featuresFromAttachLayer = [];
_.each(wrappedFeatures, function (wrappedFeature) {
bufferTasks.push(geometryEngineAsync.buffer(
[feature.geometry]
, feature.geometry.type === "polygon" ? [0] : [5]
, esriSRUnit_Meter));
}
}.bind(this));
all(bufferTasks).then(function(bufferedFeatures) {
var deff = new Deferred();
deff.resolve(bufferedFeatures, wrappedFeatures);
return deff.promise;
})
.then(this._saveNewGeometries.bind(this))
Any ideas how to pass the parameter the correct way , both on the good code side and the technical side.
I'm using Javascript with jQuery. I'd like to implement out params. In C#, it would look something like this:
/*
* odp the object to test
* error a string that will be filled with the error message if odp is illegal. Undefined otherwise.
*
* Returns true if odp is legal.
*/
bool isLegal(odp, out error);
What is the best way to do something like this in JS? Objects?
function isLegal(odp, errorObj)
{
// ...
errorObj.val = "ODP failed test foo";
return false;
}
Firebug tells me that the above approach would work, but is there a better way?
The callback approach mentioned by #Felix Kling is probably the best idea, but I've also found that sometimes it's easy to leverage Javascript object literal syntax and just have your function return an object on error:
function mightFail(param) {
// ...
return didThisFail ? { error: true, msg: "Did not work" } : realResult;
}
then when you call the function:
var result = mightFail("something");
if (result.error) alert("It failed: " + result.msg);
Not fancy and hardly bulletproof, but certainly it's OK for some simple situations.
I think this is pretty much the only way (but I am not a hardcore JavaScript programmer ;)).
What you could also consider is to use a callback function:
function onError(data) {
// do stuff
}
function isLegal(odp, cb) {
//...
if(error) cb(error);
return false;
}
isLegal(value, onError);
Yes, as you yourself mentioned, objects are the best and only way to pass data by reference in JavaScript. I would keep your isLegal function as such and simply call it like this:
var error = {};
isLegal("something", error);
alert(error.val);
The answers I have seen so far aren't implementing out parameters in JavaScript, as they are used in C# (the out keyword). They are merely a workaround that returns an object in case of an error.
But what do you do if you really need out parameters?
Because Javascript doesn't directly support it, you need to build something that is close to C#'s out parameters. Take a look at this approach, I am emulating C#s DateTime.TryParse function in JavaScript. The out parameter is result, and because JavaScript doesn't provide an out keyword, I am using .value inside the function to pass the value outside the function (as inspired by MDN suggestion):
// create a function similar to C#'s DateTime.TryParse
var DateTime = [];
DateTime.TryParse = function(str, result) {
result.value = new Date(str); // out value
return (result.value != "Invalid Date");
};
// now invoke it
var result = [];
if (DateTime.TryParse("05.01.2018", result)) {
alert(result.value);
} else {
alert("no date");
};
Run the snippet and you'll see it works: It parses the str parameter into a Date and returns it in the result parameter. Note that result needs to be initialized as empty array [], before you call the function (it can also be an object{} depending on your needs). This is required because inside the function you "inject" the .value property.
Now you can use the pattern above to write a function as the one in your question (this also shows you how to emulate the new discard parameter known as out _ in C#: In JavaScript we're passing [] as shown below):
// create a function similar to C#'s DateTime.TryParse
var DateTime = [];
DateTime.TryParse = function(str, result) {
result.value = new Date(str); // out value
return (result.value != "Invalid Date");
};
// returns false, if odb is no date, otherwise true
function isLegal(odp, errorObj) {
if (DateTime.TryParse(odp, [])) { // discard result here by passing []
// all OK: leave errorObj.value undefined and return true
return true;
} else {
errorObj.value = "ODP failed test foo"; // return error
return false;
}
}
// now test the function
var odp = "xxx01.12.2018xx"; // invalid date
var errorObj = [];
if (!isLegal(odp, errorObj)) alert(errorObj.value); else alert("OK!");
What this example does is it uses the result parameter to pass an error message as follows:
errorObj.value = "ODP failed test foo"; // return error
If you run the example it will display this message in a popup dialog.
Note: Instead of using a discard parameter as shown above, in JavaScript you could also use a check for undefined, i.e. inside the function check for
if (result === undefined) {
// do the check without passing back a value, i.e. just return true or false
};
Then it is possible to omit result as a parameter completely if not needed, so you could invoke it like
if (DateTime.TryParse(odp)) {
// ... same code as in the snippet above ...
};
I am using a callback method (similar to Felix Kling's approach) to simulate the behavior of out parameters. My answer differs from Kling's in that the callback function acts as a reference-capturing closure rather than a handler.
This approach suffers from JavaScript's verbose anonymous function syntax, but closely reproduces out parameter semantics from other languages.
function isLegal(odp, out_error) {
//...
out_error("ODP failed test foo"); // Assign to out parameter.
return false;
}
var error;
var success = isLegal(null, function (e) { error = e; });
// Invariant: error === "ODP failed test foo".
there is another way JS can pass 'out' parameters. but i believe the best ones for your situation were already mentioned.
Arrays are also passed by reference, not value. thus just as you can pass an object to a function, and then set a property of the object in the function, and then return, and access that object's property, you can similarly pass an Array to a function, set some values of the array inside the function, and return and access those values outside the array.
so in each situation you can ask yourself, "is an array or an object better?"
I'm not going to post any code but what fails to be done here in these answers is to put rhyme to reason. I'm working in the native JS arena and the problem arose that some native API calls need to be transformed because we can't write to the parameters without ugly shameful hacks.
This is my solution:
// Functions that return parameter data should be modified to return
// an array whose zeroeth member is the return value, all other values
// are their respective 1-based parameter index.
That doesn't mean define and return every parameter. Only the
parameters that recieve output.
The reason for this approach is thus: Multiple return values may be needed for any number of procedures. This creates a situation where objects with named values (that ultimately will not be in sync with the lexical context of all operations), constantly need to be memorized in order to appropriately work with the procedure(s).
Using the prescribed method, you only have to know what you called, and where you should be looking rather than having to know what you are looking for.
There is also the advantage that "robust and stupid" alogrithms can be written to wrap around the desired procedure calls to make this operation "more transparent".
It would be wise to use an object, function, or an array (all of which are objects) as a "write-back-output" parameter, but I believe that if any extraneous work must be done, it should be done by the one writing the toolkit to make things easier, or broaden functionality.
This is a one for all answer for every occaision, that keeps APIs looking the way the should at first look, rather than appearing to be and having every resemblence of a hobble-cobbled weave of spaghetti code tapestry that cannot figure out if it is a definition or data.
Congratulations, and good luck.
I'm using the webkitgtk3 and interfaceing some native C Library procs. so this proven code sample might at least serve the purpose of illustration.
// ssize_t read(int filedes, void *buf, size_t nbyte)
SeedValue libc_native_io_read (SeedContext ctx, SeedObject function, SeedObject this_object, gsize argument_count, const SeedValue arguments[], SeedException *exception) {
// NOTE: caller is completely responsible for buffering!
/* C CODING LOOK AND FEEL */
if (argument_count != 3) {
seed_make_exception (ctx, exception, xXx_native_params_invalid,
"read expects 3 arguments: filedes, buffer, nbyte: see `man 3 read' for details",
argument_count
); return seed_make_undefined (ctx);
}
gint filedes = seed_value_to_int(ctx, arguments[0], exception);
void *buf = seed_value_to_string(ctx, arguments[1], exception);
size_t nbyte = seed_value_to_ulong(ctx, arguments[2], exception);
SeedValue result[3];
result[0] = seed_value_from_long(ctx, read(filedes, buf, nbyte), exception);
result[2] = seed_value_from_binary_string(ctx, buf, nbyte, exception);
g_free(buf);
return seed_make_array(ctx, result, 3, exception);
}
The following is approach i am using. And this is answer for this question. However code has not been tested.
function mineCoords( an_x1, an_y1 ) {
this.x1 = an_x1;
this.y1 = an_y1;
}
function mineTest( an_in_param1, an_in_param2 ) {
// local variables
var lo1 = an_in_param1;
var lo2 = an_in_param2;
// process here lo1 and lo2 and
// store result in lo1, lo2
// set result object
var lo_result = new mineCoords( lo1, lo2 );
return lo_result;
}
var lo_test = mineTest( 16.7, 22.4 );
alert( 'x1 = ' + lo_test.x1.toString() + ', y1 = ' + lo_test.y1.toString() );
The usual approach to the specific use case you outlined in Javascript, and in fact most high level languages, is to rely on Errors (aka exceptions) to let you know when something out of the ordinary has occurred. There's no way to pass a value type (strings, numbers etc) by reference in Javascript.
I would just do that. If you really need to feed custom data back to the calling function you can subclass Error.
var MyError = function (message, some_other_param)
{
this.message = message;
this.some_other_param = some_other_param;
}
//I don't think you even need to do this, but it makes it nice and official
MyError.prototype = Error;
...
if (something_is_wrong)
throw new MyError('It failed', /* here's a number I made up */ 150);
Catching exceptions is a pain, I know, but then again so is keeping track of references.
If you really really need something that approaches the behavior of out variables, objects are passed by reference by default, and can handily capture data from other scopes--
function use_out (outvar)
{
outvar.message = 'This is my failure';
return false;
}
var container = { message : '' };
var result = use_out(container );
console.log(container.message); ///gives the string above
console.log(result); //false
I think this goes a some ways towards answering your question, but I think your entire approach is broken from the start. Javascript supports so many much more elegant and powerful ways to get multiple values out of a function. Do some reading about generators, closures, hell even callbacks can be nice in certain situations-- look up continuation passing style.
My point with this whole rant is to encourage anyone reading this to adapt their programming style to the limitations and capabilities of the language they're using, rather than trying to force what they learned from other languages into it.
(BTW some people strongly recommend against closures because they cause evil side-effects, but I wouldn't listen to them. They're purists. Side effects are almost unavoidable in a lot of applications without a lot of tedious backtracking and stepping around cant-get-there-from-here obstacles. If you need them, keeping them all together in a neat lexical scope rather than scattered across a hellscape of obscure pointers and references sounds a lot better to me)
The main advantage of real output parameters is direct modification of one or more scalar variables in the scope of the caller. Among the approaches proposed in other answers, only callbacks satisfy this requirement:
function tryparse_int_1(s, cb)
{ var res = parseInt(s);
cb(res);
return !isNaN( res );
}
function test_1(s)
{ var /* inreger */ i;
if( tryparse_int_1( s, x=>i=x ) )
console.log(`String "${s}" is parsed as integer ${i}.`); else
console.log(`String "${s}" does not start with an integer.`);
}
test_1("47");
test_1("forty-seven");
In this case, passing each output parameter requires five extra characters to wrap its identifier into an anonymous setter function. It is neither very readable nor easy to type frequently, so one can resort to the single most interesting property of scripting languages—their ability to do magick, such as executing strings as code.
The following example implements an extended version of the integer-parsing function above, which now has two output parameters: the resulting integer and a flag indicating whether it is positive:
/* ------------ General emulator of output parameters ------------ */
function out_lit(v)
{ var res;
if( typeof(v) === "string" )
res = '"' + v.split('\"').join('\\\"') + '"'; else
res = `${v}`;
return res;
}
function out_setpar(col, name, value)
{ if( col.outs == undefined ) col.outs = [];
col.outs[name] = value;
}
function out_setret(col, value)
{ col.ret = value; }
function out_ret( col )
{ var s;
for(e in col.outs)
{ s = s + "," + e + "=" + out_lit( col.outs[e] ); }
if( col.ret != undefined )
{ s = s + "," + out_lit( col.ret ); }
return s;
}
/* -------- An intger-parsing function using the emulator -------- */
function tryparse_int_2 // parse the prefix of a string as an integer
( /* string */ s, // in: input string
/* integer */ int, // out: parsed integer value
/* boolean */ pos // out: whether the result is positive
)
{ var /* integer */ res; // function result
var /* array */ col; // collection of out parameters
res = parseInt(s);
col = [];
out_setpar( col, int, res );
out_setpar( col, pos, res > 0 );
out_setret( col, !isNaN( res ) );
return out_ret( col );
}
In this version, passing each output parameters requires two extra characters around its identifier to embed it into a string literal, plus six characters per invocation to evaluate the result:
function test_2(s)
{ var /* integer */ int;
var /* boolean */ pos;
if( !eval( tryparse_int_2( s, "int", "pos" ) ) )
{ console.log(`String "${s}" does not start with an integer.`); }
else
{ if( pos ) adj = "positive";
else adj = "non-positive";
console.log(`String "${s}" is parsed as a ${adj} integer ${int}.`);
}
}
test_2( "55 parrots" );
test_2( "-7 thoughts" );
test_2( "several balls" );
The output of the test code above is:
String "55 parrots" is parsed as a positive integer 55.
String "-7 thoughts" is parsed as a non-positive integer -7.
String "several balls" does not start with an integer.
This solution, however, has a deficiency: it cannot handle returns of non-basic types.
Perhaps a cleaner approach is the emulation of pointers:
// Returns JavaScript for the defintion of a "pointer" to a variable named `v':
// The identifier of the pointer is that of the variable prepended by a $.
function makeref(v)
{ return `var $${v} = {set _(val){${v}=val;},get _() {return ${v};}}`; }
// Calcualtes the square root of `value` and puts it into `$root`.
// Returns whether the operation has succeeded.
// In case of an error, stores error message in `$errmsg`.
function sqrt2
( /* in number */ value, /* value to take the root of */
/* out number */ $root , /* "pointer" to result */
/* out string */ $errmsg /* "pointer" to error message */
)
{ if( typeof( value ) !== "number" )
{ $errmsg._ = "value is not a number.";
return false;
}
if( value < 0 )
{ $errmsg._ = "value is negative.";
return false;
}
$root._ = Math.sqrt(value);
return true;
}
The following test code:
function test(v)
{ var /* string */ resmsg;
var /* number */ root ; eval( makeref( "root" ) );
var /* string */ errmsg; eval( makeref( "errmsg" ) );
if( sqrt2(v, $root, $errmsg) ) resmsg = `Success: ${root}`;
else resmsg = `Error: ${errmsg}`;
console.log(`Square root of ${v}: ` + resmsg );
}
test("s" );
test(-5 );
test( 1.44);
prints:
Square root of s: Error: value is not a number.
Square root of -5: Error: value is negative.
Square root of 1.44: Success: 1.2
"Pointers" created by this method are reusable in other functions and subsequent invocations of the same function. For example, you could define a function that appends strings:
// Append string `sep' to a string pointed to by $s, using `sep` as separator:
// $s shall not point to an undefined value.
function append($s, sep, val)
{ if( $s._ != '' ) $s._ += sep;
$s._ += val;
}
and use it thus:
const sep = ", "
var s; eval( makeref("s") );
s = '';
append( $s, sep, "one" );
append( $s, sep, "two" );
append( $s, sep, "three" );
console.log( s );
It will print:
one, two, three