I ran into what seemed like very strange behavior from Dart today. There must be something wrong with how I am understanding local variables and lexical scope. Let's get into some code. The context is a testing grade conversion from numbers to letters, but that's not crucial to understand.
First, consider this code, which works as expected:
void main() {
final pairs = <List>[
[95, 'A'],
[85, 'B'],
];
for (final pair in pairs) {
int number = pair[0];
String letter = pair[1];
test('$number converts to $letter', () {
final actual = convert(number);
expect(actual, letter);
});
}
}
String convert(int value) => value >= 90 ? 'A' : 'B';
Run the tests and it passes. Change the second row of test data from 85 to 95, and the second test fails. I understand this.
Now consider this alternative implementation. Notice that the only difference is that the number and letter variables are now declared outside the for loop.
void main() {
final pairs = <List>[
[95, 'A'],
[85, 'B'],
];
int number;
String letter;
for (final pair in pairs) {
number = pair[0];
letter = pair[1];
test('$number converts to $letter', () {
final actual = convert(number);
expect(actual, letter);
});
}
}
String convert(int value) => value >= 90 ? 'A' : 'B';
Running this code as-is produces the expected results: two tests succeed, and their names are "95 converts to A" and "85 converts to B". However, now change that 85 in the test data to 95. Now, both tests fail. The names of the tests are what one would expect: "95 converts to A" and "95 converts to B."
I've tried setting a breakpoint inside the test method to figure it out. When the test is run, the first test's name is "95 converts to A," but inside that test body, the value of letter is 'B'.
I've been dealing with programming languages for a long time, but I'm dumbfounded. Can someone explain to me what is happening here? I don't understand why the two programs would behave differently.
The way the test framework works, is that it runs once to find all the tests, but doesn't actually execute the test bodies yet.
Then, the test runner runs the tests that it collected in the first pass.
Your code creates one set of variables, and assigns to them twice in the first pass, and registers two tests.
Then the tests run, and both see the latest assignment to the variables.
That's why you need to either ensure that the variables are unique to the call to test, by creating them inside the loop, or ensure the variables are initialized by a setUp call, because those are called for each test.
I'm getting error summing a List using the .fold() method:
List<int> listInt = [1, 2, 3, 4, 5, 6];
int sumList = listInt.fold(0, (p, c) => p + c);
// First Print
print(sumList);
// Second Pring
print(listInt.fold(0, (p, c) => p + c));
Printing sumList is perfectly fine, but when I print the same operation i get a compilation error:
The operator '+' can't be unconditionally invoked because the receiver can be 'null'.
Any ideas why?
A case where the Dart type system is not smart enough to guess the correct type. What happens in your second line is that fold thinks you want a Object? returned so p becomes Object?.
In the first example, the Dart type system guesses the type based on the expected returned type which is int in your case. But because print expects Object?, you are really not getting the type you expect.
The reason is that the Dart type system does not really understand the concept of defining the returned type of a method given as second argument based on the type of the first argument. So fold is often problematic here if we don't have an typed output.
We can force it to understand what we want by changing your second line to:
print(listInt.fold<int>(0, (p, c) => p + c));
And it should work as you want.
Both the collection-for-in operation and .map() method can return some manipulation of elements from a previous collection. Is there ever any reason to prefer using one over the other?
var myList = [1,2,3];
var alteredList1 = [for(int i in myList) i + 2]; //[3,4,5]
var alteredList2 = myList.map((e) => e + 2).toList(); //[3,4,5]
Use whichever is easier and more readable.
That's a deliberately vague answer, because it depends on what you are doing.
Any time you have something ending in .toList() I'd at least consider making it into a list literal. If the body of the map or where is simple, you can usually rewrite it directly to a list literal using for/in (plus if for where).
And then, sometimes it gets complicated, you need to use the same variable twice, or the map computation uses a while loop, or something else doesn't just fit into the list literal syntax.
Then you can either keep the helper function and do [for (var e in something) helperFunction(e)] or just do something.map((e) { body of helper function }).toList(). In many cases the latter is then more readable.
So, consider using a list literal if your iterable code ends in toList, but if the literal gets too convoluted, don't feel bad about using the .map(...).toList() approach.
Readability is all that really matters.
Not an expert but personally I prefer the first method. Some reasons:
You can include other elements (independent from the for loop) in the same list:
var a = [1, 2, 3];
bool include5 = true;
var b = [
1,
for (var i in a) i + 1,
if (include5) 5,
];
print(b); // [1, 2, 3, 4, 5]
Sometimes when mapping models to a list of Widgets the .map().toList() method will produce a List<dynamic>, implicit casting won't work. When you come across such an error just avoid the second method.
I am trying to figure out what accumulator and combiner do in reduce stream operation.
List<User> users = Arrays.asList(new User("John", 30), new User("Julie", 35));
int result = users.stream()
.reduce(0,
(partialAgeResult, user) -> {
// accumulator is called twice
System.out.println(MessageFormat.format("partialAgeResult {0}, user {1}", partialAgeResult, user));
return partialAgeResult + user.getAge();
},
(integer, integer2) -> {
// combiner is never called
System.out.println(MessageFormat.format("integer {0}, integer2 {1}", integer, integer2));
return integer * integer2;
});
System.out.println(MessageFormat.format("Result is {0}", result));
I notice that the combiner is never executed, and the result is 65.
If I use users.parallelStream() then the combiner is executed once and the result is 1050.
Why stream and parallelStream yield different results? I don't see any side-effects of executing this in parallel.
What is the purpose of the combiner in the simple stream version?
The problem is here. You are multiplying and not adding in your combiner.
(integer, integer2) -> {
// combiner is never called
System.out.println(MessageFormat.format("integer {0}, integer2 {1}", integer, integer2));
return integer * integer2; //<----- Should be addition
});
The combiner is used to appropriately combine various parts of a parallel operation as these operations can perform independently on individual "pieces" of the original stream.
A simple example would be summing a list of elements. You could have a variety of partial sums in a parallel operation, so you need to sum the partial sums in the combiner to get the total sum (a good exercise for you to try and see for yourself).
For a sequential stream with a mismatch between the types of the accumulator arguments or implementation( BiFunction<U,? super T,U>), you have to give combiner but that never invoked since you there is no need to combine partial result those are parallelly calculated.
So you can simplify this by just convert into partial data before reduce to avoid giving combiner.
users.stream().map(e -> e.getAge()).reduce(0, (a, b) -> a + b);
So, there is no purpose using a combiner with an accumulator like BiFunction<U,? super T,U> for sequential stream actually, but you have to provide since there is no method like
reduce(U identity, BiFunction<U,? super T,U> accumulator)
But for parallel stream combiner called.
And you are getting 1050 because your multiplying in combiner that means (30*35).
Ok this is more of a computer science question, than a question based on a particular language, but is there a difference between a map operation and a foreach operation? Or are they simply different names for the same thing?
Different.
foreach iterates over a list and performs some operation with side effects to each list member (such as saving each one to the database for example)
map iterates over a list, transforms each member of that list, and returns another list of the same size with the transformed members (such as converting a list of strings to uppercase)
The important difference between them is that map accumulates all of the results into a collection, whereas foreach returns nothing. map is usually used when you want to transform a collection of elements with a function, whereas foreach simply executes an action for each element.
In short, foreach is for applying an operation on each element of a collection of elements, whereas map is for transforming one collection into another.
There are two significant differences between foreach and map.
foreach has no conceptual restrictions on the operation it applies, other than perhaps accept an element as argument. That is, the operation may do nothing, may have a side-effect, may return a value or may not return a value. All foreach cares about is to iterate over a collection of elements, and apply the operation on each element.
map, on the other hand, does have a restriction on the operation: it expects the operation to return an element, and probably also accept an element as argument. The map operation iterates over a collection of elements, applying the operation on each element, and finally storing the result of each invocation of the operation into another collection. In other words, the map transforms one collection into another.
foreach works with a single collection of elements. This is the input collection.
map works with two collections of elements: the input collection and the output collection.
It is not a mistake to relate the two algorithms: in fact, you may view the two hierarchically, where map is a specialization of foreach. That is, you could use foreach and have the operation transform its argument and insert it into another collection. So, the foreach algorithm is an abstraction, a generalization, of the map algorithm. In fact, because foreach has no restriction on its operation we can safely say that foreach is the simplest looping mechanism out there, and it can do anything a loop can do. map, as well as other more specialized algorithms, is there for expressiveness: if you wish to map (or transform) one collection into another, your intention is clearer if you use map than if you use foreach.
We can extend this discussion further, and consider the copy algorithm: a loop which clones a collection. This algorithm too is a specialization of the foreach algorithm. You could define an operation that, given an element, will insert that same element into another collection. If you use foreach with that operation you in effect performed the copy algorithm, albeit with reduced clarity, expressiveness or explicitness. Let's take it even further: We can say that map is a specialization of copy, itself a specialization of foreach. map may change any of the elements it iterates over. If map doesn't change any of the elements then it merely copied the elements, and using copy would express the intent more clearly.
The foreach algorithm itself may or may not have a return value, depending on the language. In C++, for example, foreach returns the operation it originally received. The idea is that the operation might have a state, and you may want that operation back to inspect how it evolved over the elements. map, too, may or may not return a value. In C++ transform (the equivalent for map here) happens to return an iterator to the end of the output container (collection). In Ruby, the return value of map is the output sequence (collection). So, the return value of the algorithms is really an implementation detail; their effect may or may not be what they return.
Array.protototype.map method & Array.protototype.forEach are both quite similar.
Run the following code: http://labs.codecademy.com/bw1/6#:workspace
var arr = [1, 2, 3, 4, 5];
arr.map(function(val, ind, arr){
console.log("arr[" + ind + "]: " + Math.pow(val,2));
});
console.log();
arr.forEach(function(val, ind, arr){
console.log("arr[" + ind + "]: " + Math.pow(val,2));
});
They give the exact ditto result.
arr[0]: 1
arr[1]: 4
arr[2]: 9
arr[3]: 16
arr[4]: 25
arr[0]: 1
arr[1]: 4
arr[2]: 9
arr[3]: 16
arr[4]: 25
But the twist comes when you run the following code:-
Here I've simply assigned the result of the return value from the map and forEach methods.
var arr = [1, 2, 3, 4, 5];
var ar1 = arr.map(function(val, ind, arr){
console.log("arr[" + ind + "]: " + Math.pow(val,2));
return val;
});
console.log();
console.log(ar1);
console.log();
var ar2 = arr.forEach(function(val, ind, arr){
console.log("arr[" + ind + "]: " + Math.pow(val,2));
return val;
});
console.log();
console.log(ar2);
console.log();
Now the result is something tricky!
arr[0]: 1
arr[1]: 4
arr[2]: 9
arr[3]: 16
arr[4]: 25
[ 1, 2, 3, 4, 5 ]
arr[0]: 1
arr[1]: 4
arr[2]: 9
arr[3]: 16
arr[4]: 25
undefined
Conclusion
Array.prototype.map returns an array but Array.prototype.forEach doesn't. So you can manipulate the returned array inside the callback function passed to the map method and then return it.
Array.prototype.forEach only walks through the given array so you can do your stuff while walking the array.
the most 'visible' difference is that map accumulates the result in a new collection, while foreach is done only for the execution itself.
but there are a couple of extra assumptions: since the 'purpose' of map is the new list of values, it doesn't really matters the order of execution. in fact, some execution environments generate parallel code, or even introduce some memoizing to avoid calling for repeated values, or lazyness, to avoid calling some at all.
foreach, on the other hand, is called specifically for the side effects; therefore the order is important, and usually can't be parallelised.
Short answer: map and forEach are different. Also, informally speaking, map is a strict superset of forEach.
Long answer: First, let's come up with one line descriptions of forEach and map:
forEach iterates over all elements, calling the supplied function on each.
map iterates over all elements, calling the supplied function on each, and produces a transformed array by remembering the result of each function call.
In many languages, forEach is often called just each. The following discussion uses JavaScript only for reference. It could really be any other language.
Now, let's use each of these functions.
Using forEach:
Task 1: Write a function printSquares, which accepts an array of numbers arr, and prints the square of each element in it.
Solution 1:
var printSquares = function (arr) {
arr.forEach(function (n) {
console.log(n * n);
});
};
Using map:
Task 2: Write a function selfDot, which accepts an array of numbers arr, and returns an array wherein each element is the square of the corresponding element in arr.
Aside: Here, in slang terms, we are trying to square the input array. Formally put, we are trying to compute it's dot product with itself.
Solution 2:
var selfDot = function (arr) {
return arr.map(function (n) {
return n * n;
});
};
How is map a superset of forEach?
You can use map to solve both tasks, Task 1 and Task 2. However, you cannot use forEach to solve the Task 2.
In Solution 1, if you simply replace forEach by map, the solution will still be valid. In Solution 2 however, replacing map by forEach will break your previously working solution.
Implementing forEach in terms of map:
Another way of realizing map's superiority is to implement forEach in terms of map. As we are good programmers, we'll won't indulge in namespace pollution. We'll call our forEach, just each.
Array.prototype.each = function (func) {
this.map(func);
};
Now, if you don't like the prototype nonsense, here you go:
var each = function (arr, func) {
arr.map(func); // Or map(arr, func);
};
So, umm.. Why's does forEach even exist?
The answer is efficiency. If you are not interested in transforming an array into another array, why should you compute the transformed array? Only to dump it? Of course not! If you don't want a transformation, you shouldn't do a transformation.
So while map can be used to solve Task 1, it probably shouldn't. For each is the right candidate for that.
Original answer:
While I largely agree with #madlep 's answer, I'd like to point out that map() is a strict super-set of forEach().
Yes, map() is usually used to create a new array. However, it may also be used to change the current array.
Here's an example:
var a = [0, 1, 2, 3, 4], b = null;
b = a.map(function (x) { a[x] = 'What!!'; return x*x; });
console.log(b); // logs [0, 1, 4, 9, 16]
console.log(a); // logs ["What!!", "What!!", "What!!", "What!!", "What!!"]
In the above example, a was conveniently set such that a[i] === i for i < a.length. Even so, it demonstrates the power of map().
Here's the official description of map(). Note that map() may even change the array on which it is called! Hail map().
Hope this helped.
Edited 10-Nov-2015: Added elaboration.
Here is an example in Scala using lists: map returns list, foreach returns nothing.
def map(f: Int ⇒ Int): List[Int]
def foreach(f: Int ⇒ Unit): Unit
So map returns the list resulting from applying the function f to each list element:
scala> val list = List(1, 2, 3)
list: List[Int] = List(1, 2, 3)
scala> list map (x => x * 2)
res0: List[Int] = List(2, 4, 6)
Foreach just applies f to each element:
scala> var sum = 0
sum: Int = 0
scala> list foreach (sum += _)
scala> sum
res2: Int = 6 // res1 is empty
If you're talking about Javascript in particular, the difference is that map is a loop function while forEach is an iterator.
Use map when you want to apply an operation to each member of the list and get the results back as a new list, without affecting the original list.
Use forEach when you want to do something on the basis of each element of the list. You might be adding things to the page, for example. Essentially, it's great for when you want "side effects".
Other differences: forEach returns nothing (since it is really a control flow function), and the passed-in function gets references to the index and the whole list, whereas map returns the new list and only passes in the current element.
ForEach tries to apply a function such as writing to db etc on each element of the RDD without returning anything back.
But the map() applies some function over the elements of rdd and returns the rdd. So when you run the below method it won't fail at line3 but while collecting the rdd after applying foreach it will fail and throw an error which says
File "<stdin>", line 5, in <module>
AttributeError: 'NoneType' object has no attribute 'collect'
nums = sc.parallelize([1,2,3,4,5,6,7,8,9,10])
num2 = nums.map(lambda x: x+2)
print ("num2",num2.collect())
num3 = nums.foreach(lambda x : x*x)
print ("num3",num3.collect())