İki bayt dizisinin aynı olup olmadığını kontrol eden bu skal kod nasıl geliştirilir?

İki bayt dizisini karşılaştırmak için bir yöntemim var. Kod java tarzı ve birçok "if-else" var.

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")
  }
}

Aşağıdaki gibi denedim, ancak bu kodu çok basitleştirmedi:

(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
Bu Scala kodu olduğu için, neden onu etiketlediniz [java]?
katma yazar Raedwald, kaynak
Çünkü Java tarzı
katma yazar Freewind, kaynak
Bu soruyu codereview.stackexchange.com adresinde yayınlamak isteyebilirsiniz. "Kodumu nasıl geliştireceğim" soruları için mükemmel bir uyum.
katma yazar barjak, kaynak

5 cevap

Bunu bir akademik egzersiz olarak yapmadıkça

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

Tanım:

Belirtilen iki bayt dizisi bire eşitse, true değerini döndürür   bir diğeri. İki dizinin her iki dizinin de içermesi durumunda iki dizi eşit kabul edilir.   aynı sayıda eleman ve ilgili tüm eleman çiftleri   iki dizi eşittir. Diğer bir deyişle, iki dizi eşitse   Aynı öğeleri aynı sırayla içerir. Ayrıca iki dizi   her ikisi de boşsa referanslar eşit kabul edilir.

Bu 'java tarzı' olan varlığını itiraf ediyorum :-)

AssertionErrors'ı attığınız için, diğerlerinin tümünü kaldırabilirsiniz:

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))
  }
}

Şüphelendiğim gibi, bunu JUnit testlerinde (yani assertArray) kullanarak yapıyorsanız, sık sık yaptığım bir diziyi kullanabilirsiniz, dizilerin dize gösterimlerini karşılaştırın:

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

Bu, farklılıkların olduğu yerde size aynı sonucu verecektir (bir AssertionError).

12
katma
@Peter Bunun işe yaramayacağını düşünmüyorum, çünkü Dizilerdeki == referans eşitliği: bkz. Bu Soru-Cevap. stackoverflow.com/q/2481149/770361 Bununla birlikte, Rex'in cevabından anlaşılacağı gibi, dizileri açıkça yapmak için dizileri sardığınız gibi iş.
katma yazar Luigi Plinge, kaynak
+1: İlk test, 'a (b1 == b2) geri dönerse basitleştirilebilir;
katma yazar Peter Lawrey, kaynak
== , b1 ve b2'nin her ikisi de boşsa, doğru olur ve eğer b1 ve b2 aynı nesne ise, bu doğru olacaktır.
katma yazar Peter Lawrey, kaynak
@MatthewFarwell, True, işte bu yüzden sadece if (b1 == null || b2 == null) ile değiştirilebiliyorsa (b1 == b2)
katma yazar Peter Lawrey, kaynak
@Peter Sadece net olmak için Arrays.equals öğeleri de aynıysa, ancak nesneler farklıysa true değerini döndürür.
katma yazar Matthew Farwell, kaynak
Maalesef, yöntemde ilk testten ziyade ilk testi (java.util.Arrays.equals (b1, b2)) kastettiğinizi sanmıştım. Elbette haklısın :-)
katma yazar Matthew Farwell, kaynak

Standart kütüphane tam olarak bu amaçla sameElements sağlar:

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
katma
Hayır, bir, a1 veya a2 boşsa başarısız olur.
katma yazar user unknown, kaynak
Çalışır, basit == veya eşittir.
katma yazar Gavin, kaynak

İşte kuyruk özyinelemeli çözümüm:

@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)  
}

ve test senaryoları

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))

Bu https://gist.github.com/1322299 bağlantıya ne dersiniz?

1
katma

Matthew'un çözümüne yönelik küçük bir gelişme, sadece birinciyi değil, tüm farklılıkları geri getirmek olabilir:

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 ))
}

Test çağırma:

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
katma

Bir olası basitleştirme:

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)
}

Muhtemelen daha da geliştirilebilir, ancak en azından iç içe ve harici döngülere sahip değildir.

1
katma