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

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

ただいまの
回答率

90.50%

  • Ruby

    7899questions

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

配列の中身が条件にあうかどうか

解決済

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 753

torisan

score 233

Ruby1.9.4です。

<前提>
要素の数が0~4個の配列があります。
値は1~7,11~17,21~27のいずれかが入り、同じ数が重複する場合もあります。
並びは小さい順にソートされています。

<やりたい事>
配列の中身の内、いずれか3つの値を調べて
『十の位と一の位がそれぞれ、連続する数値の組み合わせ(順不同)であった時 フラグを立てる。』
という処理を行いたいです。

わかりにくいと思うので例を列挙します。

[]=>false
[1,12]=>false
[2,13,24]=>true #十の位と一の位がそれぞれ、連続する数値である
[4,12,23]=>true #true。一の位が4,2,3だが数値の順序は問わない
[5,6,7]=>false  #十の位が一致してしまっている
[7,11,22]=>false   #7と1は繋がったりはしない
[3,7,11,22]=>true  #余剰データがあってもいずれか3つが条件にあっていればOK
[5,13,13,24]=>true #データが重複していてもOK
[1,4,13,22]=>true #条件が合う組み合わせが2つあっても、ただのtrue

一応自前の処理は動いてはいるのですが、
あまりにも『……。』な処理だったので今回投稿した次第です。
軽い処理が望ましいですが、考え方のみでも結構ですので
お知恵を拝借頂ければと思います。
よろしくお願いします。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

check解決した方法

0

自分の回答を置いておきます。

def check0(tmp)
  tmp2=[]
    if tmp.size >= 3 then
      if tmp.size == 4 then #[1,14,17,21] を [1,14,21] と [1,17,21] に分ける
        for i in 0..2
          if tmp[i] / 10 == tmp[i + 1] / 10 then
            tmp2 = Marshal.load(Marshal.dump(tmp))
            tmp.delete_at(i + 1)
            tmp2.delete_at(i)
            break
          end
        end
      end
      tmp3 = [tmp[0] % 10,tmp[1] % 10,tmp[2] % 10].sort
      if tmp3[0] + 1  == tmp3[1] and tmp3[1] + 1 == tmp3[2] then
        tmp3 = [tmp[0] / 10,tmp[1] / 10,tmp[2] / 10].sort
        if tmp3[0] == 0 and tmp3[1] == 1 and tmp3[2] == 2 then
            return true
        end
      end
      if tmp2.size >= 3 then
        tmp3 = [tmp2[0] % 10,tmp2[1] % 10,tmp2[2] % 10].sort
        if tmp3[0] + 1  == tmp3[1] and tmp3[1] + 1 == tmp3[2] then
          tmp3 = [tmp2[0] / 10,tmp2[1] / 10,tmp2[2] / 10].sort
          if tmp3[0] == 0 and tmp3[1] == 1 and tmp3[2] == 2 then
              return true
          end
        end
      end
    end
    return false
end

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

def check(list)
  list.
    # 無駄な重複を無くします。
    uniq.
    # 10の位と1の位に分離して配列にします。
    map { |i| [i / 10, i % 10] }.
    # 3個を抜き出した全ての組み合わせを羅列します。
    combination(3).
    # 10の位と1の位それぞれをまとめた配列にします。
    map { |a| 2.times.map { |x| 3.times.map { |y| a[y][x] } } }.
    # 組み合わせのうち何れかが条件を満たせばtrueにします。
    any? do |a|
      # 10の位と1の位それぞれについて、両方条件を満たせばtrueにします。
      a.all? do |ak|
        # ソートした後に重複しながら2つ取り出してその差分がすべて1であるかを
        # 確認することで、連続している数値なのかを確認します。
        ak.sort.each_cons(2).all? { |ai| ai[1] - ai[0] == 1 }
      end
    end
end


要素数が多く、組み合わせが膨大になる場合は、combination(3).の後にlazy.を足すと、配列を作らずにtrueが見つかり次第返るようになり、メモリ消費量も抑えられます。(ただし、lazyが使えるのは2.0.0からです)
lazyを使わない場合は、any?前のmapでやっていることをany?の中ですると良いでしょう。そこは自分で工夫してみてください。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/04/03 20:19

    関数をフル活用している感じですね。
    条件の指定によっては効率の良いものができるかもしれません。
    回答ありがとうございました。

    キャンセル

0

質問文にある配列の判定はできることを確認しています。

# ary が 連続した3つの数字列をもっているかをチェックする
def has_seq?(ary)
  ary.each_cons(3) do |nums|
    return true if nums[-1] - nums[0] == 2
  end
  false
end

def check(ary)
  keta1 = ary.map { |x| x % 10 }.sort.uniq  # 1の位の数字だけを取り出す
  keta10 = ary.map { |x| x / 10 }.sort.uniq # 10の位の数字だけを取り出す

  return false unless has_seq?(keta1)
  return false unless has_seq?(keta10)
  true
end

TESTS = [
  [[], false],
  [[1, 12], false],
  [[2, 13, 24], true],    # 十の位と一の位がそれぞれ、連続する数値である
  [[4, 12, 23], true],    # true。一の位が4,2,3だが数値の順序は問わない
  [[5, 6, 7], false],     # 十の位が一致してしまっている
  [[7, 11, 22], false],   # 7と1は繋がったりはしない
  [[3, 7, 11, 22], true],  # 余剰データがあってもいずれか3つが条件にあっていればOK
  [[5, 13, 13, 24], true], # データが重複していてもOK
  [[1, 4, 13, 22], true]   # 条件が合う組み合わせが2つあっても、ただのtrue
].freeze

TESTS.each do |test|
  puts "ERROR #{test}" if test[1] != check(test[0])
end

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/04/03 20:30

    シンプルでいい感じですね。
    回答ありがとうございました。

    キャンセル

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

  • ただいまの回答率 90.50%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Ruby

    7899questions

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