I found this example of a function that accepts a callback but it's not working? - callback

This code is similar to our previous mean() function, except in the
following if block where we check to see if a callback has been
provided. If it has, then the callback is applied to each value
before being added to the total; otherwise, the total is calculated
using just the values from the array given as the first argument
mean([2,5,7,11,4]); // this should just calculate the mean << 5.8
mean([2,5,7,11,4],x => 2*x); << 11.6
function mean(array ,callback) {
if (callback) {
array.map( callback );
}
const total = array.reduce((a, b) => a + b);
return total/array.length;
}
console.log(mean([2,5,7,11,4,5],x => 2*x));

function mean(array,callback) {
if (callback) {
array = array.map( callback ); // <--- note changes here
}
const total = array.reduce((a, b) => a + b);
return total/array.length;
}
console.log(mean([2,5,7,11,4])); //5.8 fine
console.log(mean([2,5,7,11,4],x => 2*x)) // 11.6
You weren't off by much. Check out the exact definition of Array.prototype.map() The return value from that function is a new array with each element being the result of the callback function.
I will say, your question got me to review Array.prototype.map() and passing callback functions. Thanks!
Almost forgot.. See how simple my code is formatted? That makes it easy for someone to see what's going on quickly. Recommend you do the same when posting questions here in the future.

Related

Creating Seq after waiting for all results from map/foreach in Scala

I am trying to loop over inputs and process them to produce scores.
Just for the first input, I want to do some processing that takes a while.
The function ends up returning just the values from the 'else' part. The 'if' part is done executing after the function returns the value.
I am new to Scala and understand the behavior but not sure how to fix it.
I've tried inputs.zipWithIndex.map instead of foreach but the result is the same.
def getscores(
inputs: inputs
): Future[Seq[scoreInfo]] = {
var scores: Seq[scoreInfo] = Seq()
inputs.zipWithIndex.foreach {
case (f, i) => {
if (i == 0) {
// long operation that returns Future[Option[scoreInfo]]
getgeoscore(f).foreach(gso => {
gso.foreach(score => {
scores = scores.:+(score)
})
})
} else {
scores = scores.:+(
scoreInfo(
id = "",
score = 5
)
)
}
}
}
Future {
scores
}
}
For what you need, I would drop the mutable variable and replace foreach with map to obtain an immutable list of Futures and recover to handle exceptions, followed by a sequence like below:
def getScores(inputs: Inputs): Future[List[ScoreInfo]] = Future.sequence(
inputs.zipWithIndex.map{ case (input, idx) =>
if (idx == 0)
getGeoScore(input).map(_.getOrElse(defaultScore)).recover{ case e => errorHandling(e) }
else
Future.successful(ScoreInfo("", 5))
})
To capture/print the result, one way is to use onComplete:
getScores(inputs).onComplete(println)
The part your missing is understanding a tricky element of concurrency, and that is that the order of execution when using multiple futures is not guaranteed.
If your block here is long running, it will take a while before appending the score to scores
// long operation that returns Future[Option[scoreInfo]]
getgeoscore(f).foreach(gso => {
gso.foreach(score => {
// stick a println("here") in here to see what happens, for demonstration purposes only
scores = scores.:+(score)
})
})
Since that executes concurrently, your getscores function will also simultaneously continue its work iterating over the rest of inputs in your zipWithindex. This iteration, especially since it's trivial work, likely finishes well before the long-running getgeoscore(f) completes the execution of the Future it scheduled, and the code will exit the function, moving on to whatever code is next after you called getscores
val futureScores: Future[Seq[scoreInfo]] = getScores(inputs)
futureScores.onComplete{
case Success(scoreInfoSeq) => println(s"Here's the scores: ${scoreInfoSeq.mkString(",")}"
}
//a this point the call to getgeoscore(f) could still be running and finish later, but you will never know
doSomeOtherWork()
Now to clean this up, since you can run a zipWithIndex on your inputs parameter, I assume you mean it's something like a inputs:Seq[Input]. If all you want to do is operate on the first input, then use the head function to only retrieve the first option, so getgeoscores(inputs.head) , you don't need the rest of the code you have there.
Also, as a note, if using Scala, get out of the habit of using mutable vars, especially if you're working with concurrency. Scala is built around supporting immutability, so if you find yourself wanting to use a var , try using a val and look up how to work with the Scala's collection library to make it work.
In general, that is when you have several concurrent futures, I would say Leo's answer describes the right way to do it. However, you want only the first element transformed by a long running operation. So you can use the future return by the respective function and append the other elements when the long running call returns by mapping the future result:
def getscores(inputs: Inputs): Future[Seq[ScoreInfo]] =
getgeoscore(inputs.head)
.map { optInfo =>
optInfo ++ inputs.tail.map(_ => scoreInfo(id = "", score = 5))
}
So you neither need zipWithIndex nor do you need an additional future or join the results of several futures with sequence. Mapping the future just gives you a new future with the result transformed by the function passed to .map().

Protractor- ElementFinder returning unexpected values

I am writing a protractor test case to compare the name(s) of the displayed data is same as the searched name.
Even though my test case works fine, I am not able to understand what is happening. Because when i expect the name to compare, it compares as expected, but when i print the elementFinder's(rowData)(i have attached the output screen shot here) value in console.log, it show a huge list of some values which i am not able to understand?
PS: I am a newbie to protractor`
This is the testCase:
it('should show proper data for given last name', function () {
var searchValue='manning';
searchBox.sendKeys(searchValue);
search.click();
element.all(by.binding('row.loanNumber')).count().then(function(value) {
var loanCount = value;
for (var i = 0; i < loanCount; i++) {
var rowData = element.all(by.binding('row.borrowerName')).get(i).getText();
expect(rowData).toMatch(searchValue.toUpperCase());
console.log(rowData,'*****',searchValue.toUpperCase());
}
});
});`
And give me valuable suggestions about my style of code
rowData is a promise (not a value), so when you console.log it, you get the promise object
Protractor patches Jasmine to automatically resolve promises within the expect(), so that's how it knows to resolve the value and compare to the expected result.
If you want to console.log the value, you need to resolve the promise with .then() to get the value.
rowData.then(function(rowDataText) {
console.log(rowDataText);
)}
This is pretty much everyone's first question when they start using protractor. You will want to learn how promises work if you want a good understanding of how to manipulate them.

For loop not executing in protractor

I am able to get the count value with the following:
element.all(by.options('type as type for type in types')).then(function(elems){
return elems.length;
})
.then(function(count){
cnt = count;
});
Then later in the code I want to use cnt in a for loop where I also use closure:
for(var x = 1;x < cnt; x++){
search_options(x);
}
function test(y){
console.log('input'+y);
}
function search_options(input){
it('tess', function(){
test(input);
});
}
The problem is that the for does not execute.
Any tips or suggestions, guidance is appreciated or point out any errors.
I have read about IIFE but I find most samples use arrays, I believe 'cnt' has resolved
Unfortunately, I have to use the for loop. 'each' is not suitable.
The problem is that cnt would only be set when the promise would be resolved by the control flow mechanism. The for loop would be executed earlier.
Instead, define cnt as a promise and resolve it in your test:
cnt = element.all(by.options('type as type for type in types')).count();
cnt.then(function (actualCount) {
for(var x = 1; x < actualCount; x++){
search_options(x);
}
});
Also see: Using protractor with loops.
Also, I'm not exactly sure if dynamically creating its this way would actually work, here are some relevant threads:
https://github.com/jasmine/jasmine/issues/830
Can I dynamically create a test spec within a callback?

FB.api() object type as a variable

I have written the code below:
function processLWO(lwo,type)
{
FB.api('me/'+lwo,
'post',
{shoe :'<%=sItemURL%>',object :'<%=sItemURL%>'},
function (response)
{
//code
}
);
}
My problem is with the following line of code:
//Code that works - Code A
shoe :'<%=sItemURL%>',object :'<%=sItemURL%>'
//Code I want to use - Code B
type.toString():'<%=sItemURL%>'
Code A works but I want to implement Code B because it is more flexible however Code B returns a Javascript error stating the original function that lead to this function is undefined. I understand type.toString() should be a Facebook object (for example, shoe or object) but if type.toString() is processed and returns a value then it would be evaluated as a valid object type.
Any suggestions how to solve this? Code A is just so lazy/stupid....
var params = {};
params[type] = <%=sItemURL%>'
FB.api('/me/' + lwo, 'POST', params, ...

What is wrong with the below statement(C#3.0 / Lambda)

what is wrong in the below
Enumerable.Range(0, objEntityCode.Count - 1).Select(i =>
{
options.Attributes[i] = new EntityCodeKey
{
EntityCode = objEntityCode[i].EntityCodes
, OrganizationCode = Constants.ORGANIZATION_CODE };
})
.ToArray();
Throwing error The type arguments for method 'System.Linq.Enumerable.Select(System.Collections.Generic.IEnumerable, System.Func)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
But this works
Enumerable.Range(0, objEntityCode.Count - 1).ToList().ForEach(i =>
{
options.Attributes[i] = new EntityCodeKey
{
EntityCode = objEntityCode[i].EntityCodes
, OrganizationCode = Constants.ORGANIZATION_CODE
};
}
);
Using C#3.0.
Purpose: I am learning LINQ / LAMBDA and trying to do the same program in different way.
Thanks.
As I stated in a comment - your lambda expression doesn't return anything. Therefore it can't be used in a projection. Select is meant to transform a sequence of items of one type into a sequence of items of another type. You're not doing any transforming in your lambda expression - you've just got an assignment.
Now you could do this:
Enumerable.Range(0, objEntityCode.Count - 1).Select(i =>
{
return options.Attributes[i] = new EntityCodeKey
{
EntityCode = objEntityCode[i].EntityCodes,
OrganizationCode = Constants.ORGANIZATION_CODE
};
})
.ToArray();
I wouldn't recommend it though. I appreciate you're currently learning about LINQ and lambda expressions, but it's worth learning when not to use them too - and this looks like a situation where you really, really shouldn't use them.
Look at what you have inside the Select and ForEach method calls:
options.Attributes[i] = new EntityCodeKey
{
EntityCode = objEntityCode[i].EntityCodes
, OrganizationCode = Constants.ORGANIZATION_CODE
};
This is essentially an Action<int> -- that is, code that does something but doesn't return something. This is why it makes sense within ForEach but not Select -- Select expects (in this case) a Func<int, T> -- code that returns something (of some type T). Since you are simply assigning Attributes[i] to a new EntityCodeKey, this code does not fall under the umbrella of what you would normally find within a Select call.
Note that technically, the above code actually would return something -- namely, the value stored in options.Attributes[i] -- if you removed the semicolon from the end. Why? Two reasons:
A single-line lambda expression (not terminating in a semi-colon) returns whatever it evaluates to. This is why something like person => person.Name can actually be interpreted as a Func<Person, string>.
An assignment operation evaluates to the assigned value. This is why you can write x = y = z -- because y = z actually evalutes to the newly assigned value of y.
So it's true: your code, sans semi-colon, would actually evaluate to options.Attributes[i]. But writing the code in this way would be, in my opinion anyway, pretty confusing.