37

I read some code where someone did this in Ruby:

puts ('A'..'Z').to_a.join(',')

output:

A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z

Is there something in Javascript that will allow this to be done just as easy? if not, is there Node module that allows for something similar?

Phrogz
  • 296,393
  • 112
  • 651
  • 745
EhevuTov
  • 20,205
  • 16
  • 66
  • 71

13 Answers13

27

If you're using ES6, you can generate a sequence using Array.from() by passing in an array-like object for the length of the range, and a map function as a second argument to convert the array key of each item in the range into a character using String.fromCharCode():

Array.from({ length: 26 }, (_, i) => String.fromCharCode('A'.charCodeAt(0) + i));

You can also use the Array constructor (note: ES6 allows constructors to be invoked either with a function call or with the new operator) to initialize an array of the desired default length, fill it using Array.fill(), then map through it:

Array(26).fill().map((_, i) => String.fromCharCode('A'.charCodeAt(0) + i));

The same can be accomplished with the spread operator:

[...Array(26)].map((_, i) => String.fromCharCode('A'.charCodeAt(0) + i));

The above three examples will return an array with characters from A to Z. For custom ranges, you can adjust the length and starting character.

For browsers that don't support ES6, you can use babel-polyfill or core-js polyfill (core-js/fn/array/from).

If you're targeting ES5, I would recommend the Array.apply solution by @wires which is very similar to this one.

Lastly, Underscore/Lodash and Ramda have a range() function:

_.range('A'.charCodeAt(0), 'Z'.charCodeAt(0) + 1).map(i => String.fromCharCode(i));
Community
  • 1
  • 1
Brian Stanback
  • 369
  • 3
  • 8
17

Javascript doesn't have that functionality natively. Below you find some examples of how it could be solved:

Normal function, any characters from the base plane (no checking for surrogate pairs)

function range(start,stop) {
  var result=[];
  for (var idx=start.charCodeAt(0),end=stop.charCodeAt(0); idx <=end; ++idx){
    result.push(String.fromCharCode(idx));
  }
  return result;
};

range('A','Z').join();

The same as above, but as a function added to the array prototype, and therefore available to all arrays:

Array.prototype.add_range = function(start,stop) {
  for (var idx=start.charCodeAt(0),end=stop.charCodeAt(0); idx <=end; ++idx){
    this.push(String.fromCharCode(idx));
  }
  return this;
};

[].add_range('A','Z').join();

A range from preselected characters. Is faster than the functions above, and let you use alphanum_range('A','z') to mean A-Z and a-z:

var alphanum_range = (function() {
  var data = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'.split('');
  return function (start,stop) {
    start = data.indexOf(start);
    stop = data.indexOf(stop);
    return (!~start || !~stop) ? null : data.slice(start,stop+1);
  };
})();

alphanum_range('A','Z').join();

Or any character from the ascii range. By using a cached array, it is faster than the functions that build the array every time.

var ascii_range = (function() {
  var data = [];
  while (data.length < 128) data.push(String.fromCharCode(data.length));
  return function (start,stop) {
    start = start.charCodeAt(0);
    stop = stop.charCodeAt(0);
    return (start < 0 || start > 127 || stop < 0 || stop > 127) ? null : data.slice(start,stop+1);
  };
})();

ascii_range('A','Z').join();
some
  • 48,070
  • 14
  • 77
  • 93
7
var chars = [].concat.apply([], Array(26))
              .map(function(_, i) { return String.fromCharCode(i+65); })
              .join();

The .map function could be a function generator that could be used for different character sets.

function charRange(start) {
    var base = start.charCodeAt(0);
    return function(_, i) { return String.fromCharCode(i + base); };
}

And you may also want to create a "full" Array helper.

function fullArray(len) { return [].concat.apply([], Array(len)); }

Then use them like this.

var chars = fullArray(26).map(charRange("A"))
                         .join();
gray state is coming
  • 2,107
  • 11
  • 20
  • Nice, functional style is IMO waaaay more readable than for loop based answers. This answers deserves more upvotes – wires Jun 01 '14 at 13:27
6

TL;DR

// ['a', .. , 'z']
Array.apply(null, {length: 26})
    .map(function (x,i) { return String.fromCharCode(97 + i) });

Or even

function range(first, last) {
    var a = first.charCodeAt(0)
    var b = last.charCodeAt(0) + 1
    return Array.apply(null, {length: Math.abs(b - a)})
      .map(function (x,i) { return String.fromCharCode(Math.min(a, b) + i) });
}
range('K','M') // => ['K','L','M']
range('$','z') // => "$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz"

I think this can be expressed clearest in a functional way: map [0 .. 25] to ['a' .. 'z'].

We can use fromCharCode(n) to convert a number into a string. To find the numerical value corresponding to a character we need it's inverse function, toCharCode(s):

var toCharCode = function(s){ return s.charCodeAt(0) } // 'a' => 97, 'b' => 98, ..

Then the rest is easy:

Array.apply(null, {length: 26})
     .map(function (x,i) { return String.fromCharCode(97 + i) });

Constructs an array of 26 undefined's: [undefined, ... , undefined]. Then map index i of each value to 97 + i == 'a'.charCodeAt(0) + i (for uppercase start at 'A' => 65).

This first line might need some explanation. What we are effectively doing is the same as Array(1,2,3) == [1,2,3]. Instead of passing an actual array to apply, we pass something that quacks like an array (has the length property). This results in calling Array(undefined, .. , undefined).

See apply and "generic array-like object" for more infomation.

wires
  • 4,718
  • 2
  • 35
  • 31
5

Take a look at the answer from kannebec for a similar question.

Does JavaScript have a method like "range()" to generate an array based on supplied bounds?

If you don't want to add an own function, but in one line:

var abc = 
(function(){var output = []; for(var i='A'.charCodeAt(0); i <= 'Z'.charCodeAt(0); i++)
    output.push(String.fromCharCode(i)); return output;})().join(',');
Community
  • 1
  • 1
Marc J. Schmidt
  • 8,302
  • 4
  • 34
  • 33
3

CoffeeScript compiles to javascript, and it has numeric ranges:

(String.fromCharCode(x+64) for x in [1..26]).join(",")

Here's a link to this script in the coffeescript.org site. You can see what javascript it compiles to, and run it in your browser live.

(And yes, you can use coffeescript for Node.js)

Community
  • 1
  • 1
Mark Thomas
  • 37,131
  • 11
  • 74
  • 101
3

Slightly different approach

String.fromCharCode(..." ".repeat(26).split("").map((e,i)=>i+'A'.charCodeAt()))

prints

"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
test30
  • 3,496
  • 34
  • 26
  • This is the way a Sring master thinks. A lot of cool answers, reflecting different ways of thinking about the problem. – dkloke Jan 14 '18 at 08:32
2

https://stackoverflow.com/a/64599169/8784402

Generate Character List with one-liner

const charList = (a,z,d=1)=>(a=a.charCodeAt(),z=z.charCodeAt(),[...Array(Math.floor((z-a)/d)+1)].map((_,i)=>String.fromCharCode(a+i*d)));

console.log("from A to G", charList('A', 'G'));
console.log("from A to Z with step/delta of 2", charList('A', 'Z', 2));
console.log("reverse order from Z to P", charList('Z', 'P', -1));
console.log("from 0 to 5", charList('0', '5', 1));
console.log("from 9 to 5", charList('9', '5', -1));
console.log("from 0 to 8 with step 2", charList('0', '8', 2));
console.log("from α to ω", charList('α', 'ω'));
console.log("Hindi characters from क to ह", charList('क', 'ह'));
console.log("Russian characters from А to Я", charList('А', 'Я'));
For TypeScript
const charList = (p: string, q: string, d = 1) => {
  const a = p.charCodeAt(0),
    z = q.charCodeAt(0);
  return [...Array(Math.floor((z - a) / d) + 1)].map((_, i) =>
    String.fromCharCode(a + i * d)
  );
};
nkitku
  • 4,779
  • 1
  • 31
  • 27
1

Maybe this function will help you.

function range ( low, high, step ) {    // Create an array containing a range of elements
    // 
    // +   original by: _argos

    var matrix = [];
    var inival, endval, plus;
    var walker = step || 1;
    var chars  = false;

    if ( !isNaN ( low ) && !isNaN ( high ) ) {
        inival = low;
        endval = high;
    } else if ( isNaN ( low ) && isNaN ( high ) ) {
        chars = true;
        inival = low.charCodeAt ( 0 );
        endval = high.charCodeAt ( 0 );
    } else {
        inival = ( isNaN ( low ) ? 0 : low );
        endval = ( isNaN ( high ) ? 0 : high );
    }

    plus = ( ( inival > endval ) ? false : true );
    if ( plus ) {
        while ( inival <= endval ) {
            matrix.push ( ( ( chars ) ? String.fromCharCode ( inival ) : inival ) );
            inival += walker;
        }
    } else {
        while ( inival >= endval ) {
            matrix.push ( ( ( chars ) ? String.fromCharCode ( inival ) : inival ) );
            inival -= walker;
        }
    }

    return matrix;
}

console.log(range('A','Z')) 
// ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]

This is not mine, taken from: http://javascript.ru/php/range

1

No, JavaScript does not have any built-in Range object. You would need to write a function to create an abstract Range, and then add a to_a method for the equivalence.

For fun, here's an alternative way to get that exact output, with no intermediary strings.

function commaRange(startChar,endChar){
  var c=','.charCodeAt(0);
  for (var a=[],i=startChar.charCodeAt(0),e=endChar.charCodeAt(0);i<=e;++i){
    a.push(i); a.push(c);
  }
  a.pop();
  return String.fromCharCode.apply(String,a);
}

console.log(commaRange('A','J')); // "A,B,C,D,E,F,G,H,I,J"

For Node.js, there is the Lazy module.

Phrogz
  • 296,393
  • 112
  • 651
  • 745
0
function range(r, x) {
    var c1 = r.charCodeAt(0)+1, c2 = r.charCodeAt(3), s = r[0];
    if(c1 && c2)while (c1 <= c2) s += (x || "") + String.fromCharCode(c1++);
    return s;
}

range("A--S", ",");
Diode
  • 24,570
  • 8
  • 40
  • 51
0
var range = [];
for(var i = 65; i < 91; i++)
{
 range.push(String.fromCharCode(i));
}
range = range.join(',');

gives range a-z, but i like the function option of some too.

Jonathan Joosten
  • 1,499
  • 12
  • 12
0
> let charRange = (start, end) => Array.from(new Array(end.charCodeAt(0) - start.charCodeAt(0) + 1)).map((e,i) => String.fromCharCode(start.charCodeAt(0) + i));
[Function: charRange]
> charRange('B','X');
[
  'B', 'C', 'D', 'E', 'F',
  'G', 'H', 'I', 'J', 'K',
  'L', 'M', 'N', 'O', 'P',
  'Q', 'R', 'S', 'T', 'U',
  'V', 'W', 'X'
]