いろんな言語で数値のrangeを作って文字列でjoinした


次の処理を色んな言語[^1]で書いてみた。[^2]言語ごとに特徴が出てて面白かったです。

[^1]: 自分が触ったことがある言語だけなので、そんなに多くはないです。

[^2]: もとはJava8でrangeが作れるのか調べていて脱線した。

「range的な関数で作った`1`から始まる数列を、join的な関数で`,`区切りでくっつける。」




### スクリプト言語

#### perl

```perl
# perl 5, version 18, subversion 2 (v5.18.2)

# 終端を含む
print(join(",", (1..10)), "\n")
#=> 1,2,3,4,5,6,7,8,9,10
```

#### php

```php
# PHP 7.0.6

# 終端を含む
echo join(",", range(1, 10)), "\n";
#=> 1,2,3,4,5,6,7,8,9,10
```

* `join`関数は`implode`関数のエイリアスなので、`implode(",", range(1, 10));`でもOK。

#### ruby

```ruby
# ruby 2.2.3

# 終端を含まない
puts (1...10).map(&:to_s).join(",")
#=> 1,2,3,4,5,6,7,8,9

# 終端を含む
puts (1..10).map(&:to_s).join(",")
#=> 1,2,3,4,5,6,7,8,9,10
```

* `..`と`...`がどっちがどっちかいつも不安になる。

#### python

```python
# Python 3.5.1

# 終端を含まない
print(",".join(map(str, range(1, 10))))
#=> 1,2,3,4,5,6,7,8,9
```

* 2系の場合、そのままだと上記の`print`関数はエラーになる。 `from __future__ import print_function`しておけば動く。
* 3系の`range`関数の実装は、2系だと`xrange`関数のほうが近いらしい。これらは遅延評価されるが、2系`range`関数はその範囲の値を全て最初にメモリに展開するようです。  

#### javascript

```javascript
// node v6.2.1

s1 = [...Array(10).keys()].map(n => n+1).join(',');
console.log(s1);
//=> 1,2,3,4,5,6,7,8,9,10

s2 = Array.from(Array(10).keys()).map(n => n+1).join(',')
console.log(s2);
//=> 1,2,3,4,5,6,7,8,9,10

// 終端を含まない by Underscore.js
s3 = _.range(1, 10).join(',');
console.log(s3);
//=> 1,2,3,4,5,6,7,8,9

// 終端を含まない by immutable-js
s4 = Immutable.Range(1, 10).toArray().join(',');
console.log(s4);
//=> 1,2,3,4,5,6,7,8,9
```

* 素のJSで`1`から始まるrangeを直接取得する方法が分からなかった。。




### JVM言語

#### java

```java
package jp.sample;

import java.util.stream.IntStream;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) throws Exception {
        // 終端を含まない
        String s1 = String.join(",", IntStream.range(1, 10).boxed().map(n -> n.toString()).collect(Collectors.toList()));
        System.out.println(s1);
        //=> 1,2,3,4,5,6,7,8,9

        // 終端を含む
        String s2 = String.join(",", IntStream.rangeClosed(1, 10).boxed().map(n -> n.toString()).collect(Collectors.toList()));
        System.out.println(s2);
        //=> 1,2,3,4,5,6,7,8,9,10
    }
}
```


#### scala

```scala
// Scala 2.10.6

// 終端を含まない (1)
println(Range(1, 10).mkString(","))
//=> 1,2,3,4,5,6,7,8,9

// 終端を含まない (2)
println((1 until 10).mkString(","))
//=> 1,2,3,4,5,6,7,8,9

// 終端を含む
println((1 to 10).mkString(","))
//=> 1,2,3,4,5,6,7,8,9,10
```

#### clojure

```clojure
; Clojure 1.8.0

(require '[clojure.string :refer [join]])

; 終端を含まない (1)
(println (join \, (range 1 10)))
;=> 1,2,3,4,5,6,7,8,9

; 終端を含まない (2) スレッディングマクロ
(->> 10 (range 1) (join \,) println)
;=> 1,2,3,4,5,6,7,8,9
```


### CLR言語

#### c-sharp

```csharp
// mono-3.2.8.0 (C#5, CLI4.5)

public class Hello{
    public static void Main(){
        // 終端を含む
        System.Console.WriteLine(string.Join(",", System.Linq.Enumerable.Range(1, 10)));
        //=> 1,2,3,4,5,6,7,8,9,10
    }
}
```

#### f-sharp

```fsharp
// F# 3.0 (Open Source Edition) / mono-3.2.8.0

// 終端を含む
System.Console.WriteLine([1..10] |> List.map (fun n -> n.ToString()) |> String.concat ",")
//=> 1,2,3,4,5,6,7,8,9,10
```


### システムプログラミング言語

#### rust

```rust
// rustc 1.8.0

fn main() {
    // 終端を含まない
    let s: String = (1..10).map(|n| n.to_string()).collect::<Vec<String>>().join(",");
    println!("{}", s)
    //=> 1,2,3,4,5,6,7,8,9
}
```

#### go

```go
// go 1.4.2

package main
import (
    "fmt"
    "strings"
    "strconv"
)

func main(){
    var a []string = make([]string, 10)
    for i := 0; i < 10; i++ {
        a[i] = strconv.Itoa(i+1)
    }
    fmt.Println(strings.Join(a, ","))
    //=> 1,2,3,4,5,6,7,8,9,10
}
```

* rangeを直接作る方法は見つけられなかった。。

### その他

#### swift

```swift
// Swift version 2.2

// 終端を含まない
print((1..<10).map { n in String(n) }.joinWithSeparator(","))
//=> 1,2,3,4,5,6,7,8,9

// 終端を含む
print((1...10).map { n in String(n) }.joinWithSeparator(","))
//=> 1,2,3,4,5,6,7,8,9,10
```

#### haskell

```haskell
-- GHCi, version 7.10.3

-- 終端を含まない (1) 
putStrLn (intercalate "," (map (\n -> show n) [1..10]))
-- => 1,2,3,4,5,6,7,8,9

-- 終端を含まない (2) リスト内包
putStrLn (intercalate "," [show n | n <- [1..10]])
-- => 1,2,3,4,5,6,7,8,9
```

#### shell

```sh
# zsh version 5.0.8

# 終端を含む
a=`seq -s"," 1 10` && echo ${a%,}
#=> 1,2,3,4,5,6,7,8,9,10
```

* 変数`a`を使っているので、なんとなく他とやり方が違う感じがあるが、自分にはここまでしか分からなかった。
* shellはまだまだやり方がたくさんありそう。




## まとめ

メソッドをチェーンして書ける言語はどれもだいたい同じ感じになった。

rangeオブジェクトみたいなのを直接作れる言語の場合、要素の型がだいたい数値になると思うけど、それを文字列に変換（map）する一手間がある言語とない言語と。強い型付け/弱い型付けの違い以外に`join`的関数が内部で`toString()`的処理をするように実装してるかどうかの違いも関わってくる。

`..`とか`...`で作られるrangeオブジェクトに終端の数値が含まれるかどうかが、言語によってまちまち。覚えるのの諦めがついた。

Scalaの`mkString`は各言語の`join`的関数の上位互換だと思う。とても便利。



## 参考

* perl
    * [http://7ujm.net/Perl/perl.html](http://7ujm.net/Perl/perl.html)
* javascript
    * [JavascriptでRubyのRange#to_aのような配列を返す方法 - rochefort's blog](http://rochefort.hatenablog.com/entry/2015/01/08/005043)
* python
    * [Python: range と xrange | CUBE SUGAR STORAGE](http://momijiame.tumblr.com/post/53841042855/python-range-%E3%81%A8-xrange)
* scala
    * [Scalaのコレクションとかについて - Qiita](http://qiita.com/544/items/f36c018d0568156d09cb#2-2)
* go
    * [go - is there a way to iterate over a range of integers in golang? - Stack Overflow](http://stackoverflow.com/questions/21950244/is-there-a-way-to-iterate-over-a-range-of-integers-in-golang)
    * [急いで学ぶGo lang#7 range・Array・slice・map ｜ Developers.IO](http://dev.classmethod.jp/go/golang-7/)
    * [Golangでの文字列・数値変換 - 小野マトペの納豆ペペロンチーノ日記](http://matope.hatenablog.com/entry/2014/04/22/101127)
    * [strings - The Go Programming Language](https://golang.org/pkg/strings/#Join)
* c++
    * [Is there a compact equivalent to Python range() in C++/STL - Stack Overflow](http://stackoverflow.com/questions/13152252/is-there-a-compact-equivalent-to-python-range-in-c-stl)
    * [http://kaworu.jpn.org/cpp/std::iota](http://kaworu.jpn.org/cpp/std::iota)
* swift
    * [Swiftで配列をjoin(結合)して文字列にする方法 | Swift2.2 Web入門書](http://swift.tecc0.com/?p=160)
    * [SwiftのRangeは配列ではない - Qiita](http://qiita.com/karupanerura/items/425b00839c1c358c2d7a)
* c#
    * [いろいろな方法で1から100までを出力する - Qiita](http://qiita.com/muro/items/330c6c5a059436bb497b)
    * [【C#/LINQ】LINQの学習　その(4) 9×9表を一行で出力する – ザワプロ！](http://zawapro.com/?p=1285)
    * [C# - 配列を結合して文字列にする](http://jeanne.wankuma.com/tips/csharp/string/join.html)
* f#
    * [Ranges A to B where A > B in F# - Stack Overflow](http://stackoverflow.com/questions/878721/ranges-a-to-b-where-a-b-in-f)
    * [f# interactive - F#: String.Join and |> operator - Stack Overflow](http://stackoverflow.com/questions/4278531/f-string-join-and-operator)
    * [F#の文字列操作関数を調べてみた - komorebikoboshiのブログ](http://komorebikoboshi.hatenablog.com/entry/2013/04/09/233613)
    * [http://stackoverflow.com/questions/12202626/int-and-string-f](Int and String F# - Stack Overflow)