Well a map operation in Computer Science is a typically a type of higher-order function that returns a function that transforms some data set. (Higher-order function is the name for a function that takes a function as an input type and returns a function as a return type).
Going back to my point: It doesn't mean map as in paper, it means map as in "map to". A musician with no maths knowledge, when describing reading sheet music, could explain it what they do as "I map the note on the sheet to the strings I need to pluck on the guitar". This is valid and correct english, not mathematical double speak intended to confuse.
Map was chosen as the name for the operation because of "to map to", nothing to do with the physical map except that the physical map is the source of the verbage of "map to" via creating a map being "mapping out the landscape", and language just kinda evolved from there, with the act of going from one thing to another through some process becoming also known as mapping (like going from the physical land to a map), and then that getting shortened down to map and so the grammar rules kicking in made it become "to map to".
English not only allows for these kinda of dual meanings, but is rife with them. I already used several in this post alone so far. Like mean - Depending on context, it could refer to "to convey the meaning of", or could mean that something is "cruel".
For the map HOF, an example implementation of the map operation, albeit an inefficient one, in Javascript may be:
function map(transformation) {
return prev => {
const output = []
for(const item of prev) {
output.push(transformation(item))
}
return output
}
}
const doubleEveryItem = map(x => x * 2)
console.log(doubleEveryItem([1,2,3]))
// outputs [2, 4, 6]
That's basically what the Array.map in Javascript does, but it's implemented as a member function instead of a HOF. A more efficient approach would be to chain Javascript iterables together so you don't create any intermediate arrays.
The member function on Arrays is currently easier to use and chain, but less flexible. This is why there's a push for Javascript to get a
pipeline operator. Would let you write the code as something like:
[1,2,3] |> map (x => x * 2) |> (x => console.log(x))
If dealing with iterables you may need to instead write:
[1,2,3] |> map (x => x * 2) |> toArray
if you wanted to go back to an array at the end.
For more complex examples, chaining map/filter/reduce is so much easier to follow step-by-step than a for loop. You don't need the intermediate arrays when it's all deferred until that toArray.
[1,2,3,4,5]
|> filter (x => x % 2 == 0)
|> map (x => x * 2)
|> flatmap (x => [x, x ** 2])
|> distinct
|> toArray
would result in
filter: throws away 1,3,5
map: doubles 2, 4 to 4, 8
flatmap: expands 4 to 4,16. expands 8 to 8, 64
distinct: throws away one of the 8s, so each item in the set is unique (distinct)
toArray: finalises to an array to 4, 16, 8, 64
Whilst you could write that was one for loop, it's harder to follow what happens step-by-step in comparison.
const data = [1,2,3,4,5]
const result = []
for (const item of data) {
if (item % 2 === 0) {
const doubled = item * 2
if (result.indexOf(doubled) === -1) {
result.push(doubled)
}
const doubledSquared = doubled ** 2
if (result.indexOf(doubledSquared ) === -1) {
result.push(doubledSquared)
}
}
}
Modifying the chain, changing a step, removing a step or adding extra steps, is also easier than with the naked for loop. That's pretty much the motivation behind the existence of map in code.
In theory it would also be possible for a compiler/runtime to automatically make the transformations concurrent without the developer needing to explicitly code that concurrency, but that's more a happy side-benefit of the approach.