

# 概要

下のコードを見てもらえるとわかるのですが、case
when文の中身で全く同じ処理が行われている箇所があります。（具体的な処理内容については無視してもらって結構です。）  
このままだと関数定義が長すぎて冗長だしlinterに怒られるので、短く端的に記述したいです。

# コード

[code]

    def minkowski_distance(vec1, vec2, p = 1)
      raise ArgumentError "ベクトルの次数を揃えてください。" if vec1.size != vec2.size
    
      case p
      when Float::INFINITY
        candidate = []
        vec1.size.times { |i| candidate << (vec1[i] - vec2[i]).abs }
        candidate.max
      when -Float::INFINITY
        candidate = []
        vec1.size.times { |i| candidate << (vec1[i] - vec2[i]).abs }
        candidate.max
      else
        sigma(1, vec1.size) { |i| (vec1[i] - vec2[i]).abs.pow p } ** (1 / p.to_f)
      end
    end
    
[/code]

# 守りたいこと

速度の関係で、`candidate = []`と`vec1.size.times { |i| candidate << (vec1[i] -
vec2[i]).abs }`は、`p`が無限大か無限小だと判明するまでやりたくありません。  
つまり、一つ上のスコープにもっていくのはやりたくないです。

下みたいなコードではさすがにダメでした。

[code]

      case p
      when Float::INFINITY || -Float::INFINITY
        candidate = []
        vec1.size.times { |i| candidate << (vec1[i] - vec2[i]).abs }
        candidate.max if p == Float::INFINITY
        candidate.min if p == -Float::INFINITY
      else
        sigma(1, vec1.size) { |i| (vec1[i] - vec2[i]).abs.pow p } ** (1 / p.to_f)
      end
    
[/code]


CC BY-SA 4.0
2023-10-26T11:43:07.363
96589
2023-10-26T14:05:34.947
53242
question
ruby
Rubyでcase...whenを効率よく端的に書きたい


when節にはカンマ区切りで式を複数書けるので、単純に以下で良いのではないかと思いますが、何か（回答の）条件を見落としてますか？  
<https://docs.ruby-lang.org/ja/latest/doc/spec=2fcontrol.html#case>

[code]

    case p
    when Float::INFINITY, -Float::INFINITY
      candidate = []
      vec1.size.times { |i| candidate << (vec1[i] - vec2[i]).abs }
      candidate.max if p == Float::INFINITY
      candidate.min if p == -Float::INFINITY
    else
      sigma(1, vec1.size) { |i| (vec1[i] - vec2[i]).abs.pow p } ** (1 / p.to_f)
    end
    
[/code]


CC BY-SA 4.0
2023-10-26T12:17:53.100
96590
2023-10-26T12:17:53.100
7291
96589
answer


[`infinite?` → `-1`, `1`, or `nil` | class Numeric | Documentation for Ruby
3.2](https://docs.ruby-lang.org/en/3.2/Numeric.html#method-i-infinite-3F)
を利用する方法もあるかと思います。

[code]

    if p.infinite? then
        candidate = []
        vec1.size.times { |i| candidate << (vec1[i] - vec2[i]).abs }
        (p.infinite? < 0) ? candidate.min : candidate.max
    else
        sigma(1, vec1.size) { |i| (vec1[i] - vec2[i]).abs.pow p } ** (1 / p.to_f)
    end
    
[/code]


CC BY-SA 4.0
2023-10-26T14:05:34.947
96592
2023-10-26T14:05:34.947
47127
96589
answer