質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

Q&A

解決済

7回答

2400閲覧

複数の数字入った配列を「人向けに」きれいにまとめて表示をさせる「きれいなロジック」を教えていただけませんか?

takataka75

総合スコア95

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

3グッド

7クリップ

投稿2017/08/01 14:57

配列の中に、
複数の番号を格納しているとき、
それをまとめて表示する「綺麗なロジック」を
教えていただけないでしょうか?

ruby

1 2data=["1","2","3","5","7","8","9","10","11","12","15","16"] 3

このようなデータがある時に

ruby

113,5,712,15,16

という
「人が見てきれいな」出力を作りたいのですが、
「綺麗なロジック」が思いつきません。

熟練の方、
短く、早く、美しいロジックを
ご教授願えないでしょうか?

私がrubyやVBAを使っているのでサンプルはrubyですが、
rubyやVBAが第一希望ですが、他の言語でもOKです。
ですがが、
「言語特有の(モジュール等を使った)ロジック」でない方がありがたいです。

mpyw, DrqYuto👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tanat

2017/08/01 15:35

まずはご自身で作成されたコードを提示して、どこがきれいではないと感じているかを質問されては?
guest

回答7

0

PHPの例が出ていないので載せておきます。ネストした配列の初期化が容易にできるPHPらしい解法です。
if文や三項演算子などによる条件分岐が1つも無いのが特徴です。

整数配列の連続区間をハイフンで連結してグループ化する定番のアレ - Qiita

php

1$data = [1, 2, 3, 4, 5, 8, 9, 10, 13, 14, 20, 22]; 2foreach ($data as $i => $v) { 3 $pairs[$v - $i][isset($pairs[$v - $i])] = $v; 4} 5foreach ($pairs as $pair) { 6 $ranges[] = implode('~', $pair); 7} 8echo implode(',', $ranges);

投稿2017/08/04 20:21

編集2017/08/04 20:45
mpyw

総合スコア5223

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

raccy

2017/08/04 21:22

そっか、別に隣と見比べるのでは無く、インデックスと値の差分でグループ化すれば良いだけだったんですね…。無駄に大変なことをしてしまった><
takataka75

2017/08/05 05:27

ありがとうございます。 一番美しいかも
退会済みユーザー

退会済みユーザー

2017/08/05 05:56

こんなのよく思いつくなぁ。。。
zohnam

2017/08/18 02:04

これすごいわー。 今まさに必要なコードだったので助かりました。
guest

0

ベストアンサー

RubyであればEnumerable#chunk_whileが使えます。

上のリンク先のマニュアルにまさしくそのような出力をするための例が載っています。それを参考にまとめて書くと次のようになります。

Ruby

1data = ["1", "2", "3", "5", "7", "8", "9", "10", "11", "12", "15", "16"] 2puts data.map(&:to_i) 3 .chunk_while { |a, b| b == a.succ } 4 .map { |x| x.size < 3 ? x : "#{x.first}#{x.last}"} 5 .join(',')

ですが、chunk_whileのような隣同士をみてグルーピングするという関数やメソッドが用意されている言語は見当たらないです(group_byのようなグルーピングであればHaskellやLINQでみらえますが)。ということで、chunk_whileでしていることをEnumerable#injectで置き換えます。

Ruby

1data = ["1", "2", "3", "5", "7", "8", "9", "10", "11", "12", "15", "16"] 2puts data.map(&:to_i) 3 .inject([]) { |a, x| a.empty? || a.last.last.succ != x ? 4 a + [[x]] : 5 a.take(a.size - 1) + [(a.last + [x])] } 6 .map { |x| x.size < 3 ? x : "#{x.first}#{x.last}"} 7 .join(',')

投稿2017/08/01 22:30

raccy

総合スコア21735

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2017/08/02 01:12

勉強になります。
guest

0

ruby で書いてみました。
行数はすこし多いですが、他の言語にも翻訳しやすいかと思います。

ruby

1# 連続した数値毎に分割する 2def seq_array(array) 3 ans = [] 4 loop { 5 break if array.empty? 6 # 数字が連続している先頭部分と残りに分割する 7 div = array.partition.with_index {|x, idx| x == idx + array[0] } 8 ans << div[0] 9 array = div[1] 10 } 11 ans 12end 13 14def seq_array_to_s(array) 15 array.map do |seq| 16 (seq.length > 2) ? "#{seq[0]}#{seq[-1]}" : seq.join(',') 17 end.join(',') 18end 19 20data = ["1", "2", "3", "5", "7", "8", "9", "10", "11", "12", "15", "16"] 21seq_array = seq_array(data.map(&:to_i).sort) 22puts seq_array_to_s(seq_array)

先頭の数字が連続している部分を取り出す処理をまず書きました。
それをループさせて残り部分が空になるまで繰り返します。(再帰で書き直すこともできるかもしれない)
すると、最初の数列全体を 連続した部分毎に分割することができます。
あとは、この分割数列を文字列化する処理を書きました。

分割処理と文字化処理が明確に分離しているので、文字列書式を変更するのは容易だと思います。

追記 2017-08-06
seq_array を loop でなく、group_by で書き直すことができました。
さらに数値範囲を示す文字をパラメータで指定できるようにしてみました。

ruby

1# 連続した数値毎に分割する 2def to_seq_array(array) 3 array.group_by.with_index {|x, idx| x - idx }.values 4end 5 6def to_range_array(seq_array, range_str = '〜') 7 seq_array.map { |seq| seq.size > 2 ? "#{seq[0]}#{range_str}#{seq[-1]}" : seq } 8end 9 10data = ["1", "2", "3", "5", "7", "8", "9", "10", "11", "12", "15", "16"] 11seq_array = to_seq_array(data.map(&:to_i)) 12 13range_array = to_range_array(seq_array) 14puts range_array.join(',') 15 16range_array = to_range_array(seq_array, "..") 17puts range_array.join(' ')

実行結果:

$ ruby xxx.rb 1〜3,5,7〜12,15,16 1..3 5 7..12 15 16

投稿2017/08/04 17:53

編集2017/08/06 13:05
katoy

総合スコア22324

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2017/08/06 05:21

勉強になります。
guest

0

初心者ですが挑戦してみました。

Ruby

1# encoding: utf-8 2 3data = ["1","2","3","5","7","8","9","10","11","12","15","16"] 4 5data.map!(&:to_i) 6 7d = (data.min..data.max).to_a 8k = d - data 9 10k.each do |_k| 11 d[d.index(_k)] = '/' 12end 13 14d = d.join(',').split('/').map do |e| 15 e = e.split(',').reject(&:empty?).map(&:to_i) 16 e.size > 2 ? "#{e.min}~#{e.max}" : e 17end 18 19puts d.reject(&:empty?).join(', ') 20# => 1~3, 5, 7~12, 15, 16 21

投稿2017/08/01 19:13

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takataka75

2017/08/03 23:23

ありがとうございました。 参考にします。
guest

0

Pythonで書いてみました。

python

1data,lst,ans = ["1","2","3","5","7","8","9","10","11","12","15","16"],[],[] 2for i,n in enumerate(data): 3 if not lst or int(n)-int(lst[len(lst)-1]) == 1: 4 lst.append(n) 5 if i == len(data)-1:ans += lst 6 else: 7 if i == len(data)-1:lst.append(n) 8 if len(lst) <= 2:ans += lst 9 else:ans += ["%s~%s"%(lst[0],str(int(lst[0])+len(lst)-1))] 10 lst.clear() 11 lst.append(n) 12print(ans) 13 14#実行結果 15['1~3', '5', '7~12', '15', '16']

投稿2017/08/01 17:22

編集2017/08/01 17:24
_Victorique__

総合スコア1392

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takataka75

2017/08/03 23:23

ありがとうございました。 参考にします。
guest

0

あまり綺麗ではないですが,Ruby で書いてみました.

ruby

1data = ["1","2","3","5","7","8","9","10","11","12","15","16"] 2 3d = data.map{|x| x.to_i}.sort.uniq 4ret = [] 5tmp = [d.shift] 6d.each do |x| 7 if tmp.last + 1 == x then 8 tmp << x 9 else 10 ret << tmp 11 tmp = [x] 12 end 13end 14ret << tmp 15 16puts ret.map{|x| 17 if x.length > 2 then 18 "#{x.first}#{x.last}" 19 elsif x.length > 1 then 20 "#{x.first}, #{x.last}" 21 else 22 "#{x.first}" 23 end 24}.join(", ") 25# 1~3, 5, 7~12, 15, 16

投稿2017/08/01 16:48

what_alnk

総合スコア147

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takataka75

2017/08/03 23:23

ありがとうございました。 参考にします。
guest

0

楽しそうだったので書いてみました。perlで

$ perl -e ' > @data=qw(1 3 5 7 8 9 10 11 12 15 16); > $i = 0; > ($start,$output) = ("",""); > foreach (sort {$a <=> $b} @data) { > if ($start eq "") { > $start=$_; > } > if ($_ + 1 != $data[$i+1]) { > if ( $start == $_ ) { > $output .= sprintf "%d,",$_; > } elsif ( $start + 1 == $_ ) { > $output .= sprintf "%d,%d,",$start,$_; > } else { > $output .= sprintf "%d-%d,",$start,$_; > } > $start = "" ; > } > $i++; > } > printf "%s\n", $output ; > ' 1,3,5,7-12,15,16,

投稿2017/08/01 16:10

scsi

総合スコア2840

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takataka75

2017/08/03 23:23

ありがとうございました。 参考にします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問