どのように2つのバイト配列が同じかどうかをチェックしているこのスカラコードを改善するには?

2バイト配列を比較する方法があります。コードはjava形式であり、多くの "if-else"があります。

def assertArray(b1: Array[Byte], b2: Array[Byte]) {
  if (b1 == null && b2 == null) return;
  else if (b1 != null && b2 != null) {
    if (b1.length != b2.length) throw new AssertionError("b1.length != b2.length")
    else {
      for (i <- b1.indices) {
        if (b1(i) != b2(i)) throw new AssertionError("b1(%d) != b2(%d)".format(i, i))
      }
    }
  } else {
    throw new AssertionError("b1 is null while b2 is not, vice versa")
  }
}

私は以下のようにしてみましたが、コードを単純化していません。

(Option(b1), Option(b2)) match {
    case (Some(b1), Some(b2)) => if ( b1.length == b2.length ) {
       for (i <- b1.indices) {
        if (b1(i) != b2(i)) throw new AssertionError("b1(%d) != b2(%d)".format(i, i))
       }
    } else {
       throw new AssertionError("b1.length != b2.length")
    }
    case (None, None) => _
    case _ => throw new AssertionError("b1 is null while b2 is not, vice versa")
}
2
これはScalaコードなので、なぜあなたは[java]タグを付けましたか?
追加された 著者 Raedwald,
それはJavaスタイルなので
追加された 著者 Freewind,
この質問をcodereview.stackexchange.comに掲載したいかもしれません。それは "自分のコードを改善する方法"の質問に最適です。
追加された 著者 barjak,

5 答え

あなたが学問的な練習としてこれをやっていない限り、

java.util.Arrays.equals(b1, b2)

説明:

指定された2つのバイト配列が1に等しい場合にtrueを返します。   別の2つの配列は、両方の配列に   同じ数の要素、および対応するすべての要素のペア   2つのアレイは等しい。言い換えれば、2つの配列は等しい   同じ要素を同じ順序で含みます。また、2つのアレイ   両方がnullの場合、参照は等しいと見なされます。

私はこれが「Javaスタイル」であることを認めます:-)

AssertionErrorsを投げているので、他のすべてのものを削除することができます:

def assertArray(b1: Array[Byte], b2: Array[Byte]): Unit = {
  if (b1 == b2) return;

  if (b1 == null || b2 == null) throw new AssertionError("b1 is null while b2 is not, vice versa")  

  if (b1.length != b2.length) throw new AssertionError("b1.length != b2.length")

  for (i <- b1.indices) {
    if (b1(i) != b2(i)) throw new AssertionError("b1(%d) != b2(%d)".format(i, i))
  }
}

もし私が疑うように、実際にJUnitテスト(これはassertArray)内でこれを使用しているのであれば、私はしばしば行うトリックを使用して配列の文字列表現を比較します:

def assertArray2(b1: Array[Byte], b2: Array[Byte]): Unit = {
  assertEquals(toString(b1), toString(b2))
}

def toString(b: Array[Byte]) = if (b == null) "null" else java.util.Arrays.asList(b:_*).toString

違いがどこにあるのか、同じ結果(AssertionError)を与えるでしょう。

12
追加された
@Peter配列上の == は参照平等なので、これはうまくいくとは思わない:このQ&Aを参照してください。あなたは明示的にそれを作るために配列をラップすることができるようにRexの答えからそれは聞こえますか?作業。
追加された 著者 Luigi Plinge,
+1:最初のテストは、(b1 == b2)returnの場合はに簡略化できます。
追加された 著者 Peter Lawrey,
== は、b1とb2が両方ともヌルであれば真であり、b1とb2が同じオブジェクトであれば真です。
追加された 著者 Peter Lawrey,
(b1 == null || b2 == null)を if(b1 == b2)に置き換えることができるのはなぜか@MatthewFarwell、
追加された 著者 Peter Lawrey,
@Peter明確にするArrays.equalsは、要素が同じであるがオブジェクトが異なる場合はtrueを返します。
追加された 著者 Matthew Farwell,
申し訳ありませんが、メソッドの最初のテストではなく、最初のテスト(java.util.Arrays.equals(b1、b2))を意味すると思いました。あなたはもちろん正しいです:-)
追加された 著者 Matthew Farwell,

標準ライブラリは、この目的のために sameElements を提供します。

scala> val a1 = Array[Byte](1, 3, 5, 7); val a2 = Array[Byte](1, 3, 5, 7); val a3 = Array[Byte](1, 3, 5, 7, 9)
a1: Array[Byte] = Array(1, 3, 5, 7)
a2: Array[Byte] = Array(1, 3, 5, 7)
a3: Array[Byte] = Array(1, 3, 5, 7, 9)

scala> a1 sameElements a2
res0: Boolean = true

scala> a1 sameElements a3
res1: Boolean = false
6
追加された
いいえ、1つ、a1またはa2がnullの場合は失敗します。
追加された 著者 user unknown,
それは動作しますが、シンプル==または等価ではありません。
追加された 著者 Gavin,

ここで私の解決策は、テール再帰を使用しています:

@scala.annotation.tailrec
def assertArray[T](b1: Array[T], b2: Array[T])(implicit m: Manifest[T]) : Unit = (b1, b2)  match{
    case (null, null) => 
    case (null, a) if a != null => throw new AssertionError 
    case (a, null) if a != null => throw new AssertionError  
    case (Array(), Array()) => 
    case _  => if (b1.length != b2.length ||  b1.head != b2.head ) throw new AssertionError  else assertArray(b1.tail,b2.tail)  
}

テストケース

assertArray(null,null)
assertArray(Array[Byte](),null)
assertArray(null,Array[Byte]())
assertArray(Array[Byte](),Array[Byte]())
assertArray(Array[Byte](),Array[Byte](1))
assertArray(Array[Byte](1,2,3),Array[Byte](1,2,3))
assertArray(Array[Byte](1,3),Array[Byte](1))

この https://gist.github.com/1322299リンクについて

1
追加された

マシューの解決策を少し改良すれば、最初のものだけでなく、すべての差分を返すことができます:

def assertArray (b1: Array[Byte], b2: Array[Byte]): Unit = {

  def diffs [T] (a: Array[T], b: Array[T]) = 
    (a.zip (b).filter (e => (e._1 != e._2)))

  if (b1 == null && b2 == null) 
    return;
  if (b1 == null || b2 == null) 
    throw new AssertionError ("b1 is null while b2 is not, vice versa")  
  if (b1.length != b2.length) 
    throw new AssertionError ("b1.length != b2.length")
  val delta = diffs (b1, b2)
  delta.map (d => throw new AssertionError ("" + delta.mkString ))
}

テスト呼び出し:

val ab = (List ((List (47, 99, 13, 23, 42).map (_.toByte)).toArray,
  (List (47, 99, 33, 13, 42).map (_.toByte)).toArray)).toArray

assertArray (ab(0), ab(1))
// java.lang.AssertionError: (13,33)(23,13)
1
追加された

1つの可能な単純化:

def assertArray(b1: Array[Byte], b2: Array[Byte]) {
    (Option(b1), Option(b2)) match {
        case (None, _) => 
            throw new AssertionError("b1 is null")
        case (_, None) => 
            throw new AssertionError("b2 is null")
        case (Some(Size(b1Size)), Some(Size(b2Size))) if b1Size != b2Size  => 
            throw new AssertionError("b1.length != b2.length")
        case (Some(b1), Some(b2)) if b1 zip b2 find (c => c._1 != c._2) isDefined => 
            throw new AssertionError("Arrays do not match")
        case _ =>//everything is OK
    }
}

object Size {
    def unapply[T](arr: Array[T]): Option[Int] = Some(arr.size)
}

おそらくさらに改善することができますが、少なくとも if と外部ループはネストされていません。

1
追加された