Because Array#each returns the receiver itself. But Array#map, maps, each current character, you passed to the block, with the current computation result.
With #map, the condition if char =~ /[A-Za-z]/ evalutated as falsy, for each passed element like " ". Thus block mapped nil while it founds " " or any element for which if condition evaluated as falsy. But #each forgets about the block result after each iteration is completed, But #map doesn't.
If you look at the output, you can see all nil(s) are in the same position of " ". This observation also dictates about the behaviour I just mentioned above.
In Ruby, every block of code, like definition of class, method definitions, block definitions returns its last statement. In your #map block, there is no statements, after the if modifier, so it reruns nil.
In Ruby >= 2.1.1 I saw method to returns its names as a symbol. But when you will invoke it, then it will return its last statement. If the method body is empty, then nil.
Look below :-
[1] pry(main)> def foo
[1] pry(main)* end
=> :foo
[2] pry(main)> foo
=> nil
[3] pry(main)> def baz
[3] pry(main)* 12
[3] pry(main)* end
=> :baz
[4] pry(main)> baz
=> 12
update
From the comment of @asquirrel, I got an idea. You could write your code a more Ruby way :-
"This is an awesome string".gsub(/[a-z]/i).map(&:next)
# => ["U", "i", "j", "t", "j", "t", "b", "o", "b",
# "x", "f", "t", "p", "n", "f", "t", "u", "s", "j", "o", "h"]
update1
j = "This is an awesome string"
array = j.split('').map do |char|
char =~ /[A-Za-z]/ ? char.next : char
end
p array
# >> ["U", "i", "j", "t", " ", "j", "t", " ", "b", "o", " ", "b",
# "x", "f", "t", "p", "n", "f", " ", "t", "u", "s", "j", "o", "h"]