Проверка двух байтовых массивов одинаковы


У меня есть способ, чтобы сравнить два байтовых массивов. Код в стиле Java, и есть много Если-нибудьов.

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


1758
3
задан 28 октября 2011 в 09:10 Источник Поделиться
Комментарии
2 ответа

Часть проблемы-это все исключения. Есть лучшие способы обработки исключений, таких как Scalaz проверки или подъема коробки. Скала сама приходит с Любой, которая не обладает особой гибкостью.

С другой стороны, вы не возвращая ничего, что на самом деле получается весь код в обратном варианта: либо у вас есть некоторые(исключение) или нет.

Теперь сам тест, за исключением проверки на null, имеет имя в Scala: sameElements. Только он не скажет вам, в чем была проблема.

Я могу придумать два способа обращения с ним. Первый-это просто небольшое улучшение по вашему шаблону:

def assertArray(b1: Array[Byte], b2: Array[Byte]) = (Option(b1), Option(b2)) match {
case (None, None) =>
case (None, _) | (_, None) => throw new AssertionError("b1 is null while b2 is not, vice versa")
case (Some(b1), Some(b2)) if b1.length == b2.length =>
(b1, b2).zipped.map(_ == _)
.zipWithIndex.find(!_._1)
.foreach {
case (_, i) => throw new AssertionError("b1(%d) != b2(%d)".format(i, i))
}
case _ => throw new AssertionError("b1.length != b2.length")
}

Иначе будет проблема во всем абсолютно. Это будет выглядеть так:

def assertArray(b1: Array[Byte], b2: Array[Byte]) = {
def isOneNull =
if ((b1 eq null) ^ (b2 eq null)) Some("b1 is null while b2 is not, vice versa")
else None

def areSizesDifferent =
if (b1.length != b2.length) Some("b1.length != b2.length")
else None

def haveDifferentElements =
(b1, b2).zipped.map(_ == _)
.zipWithIndex.find(!_._1)
.map { case (_, i) => "b1(%d) != b2(%d)" format (i, i) }

def areTheyDifferent =
if ((b1 ne null) && (b2 ne null)) areSizesDifferent orElse haveDifferentElements
else isOneNull

areTheyDifferent foreach (msg => throw new AssertionError(msg))
}

Это дольше, и ручками nullness в двух разных местах, и не защищают от nullness, но я думаю, что он читает гораздо лучше. Чтобы получить больше, чем это мне нужно Scalaz:

def assertArray(b1: Array[Byte], b2: Array[Byte]) = {
def isOneNull =
(b1 eq null) ^ (b2 eq null) option "b1 is null while b2 is not, vice versa"

def areTheyDifferent =
Option(b1) <|*|> Option(b2) flatMap {
case (b1, b2) =>
def areSizesDifferent = b1.length != b2.length option "b1.length != b2.length"

def haveDifferentElements =
(b1, b2).zipped.map(_ == _)
.zipWithIndex.find(!_._1)
.map { case (_, i) => "b1(%d) != b2(%d)" format (i, i) }

areSizesDifferent orElse haveDifferentElements
} orElse isOneNull

areTheyDifferent foreach (msg => throw new AssertionError(msg))
}

Или, идти более полноценным с Scalaz:

def assertArray(b1: Array[Byte], b2: Array[Byte]) = {
type Params = (Array[Byte], Array[Byte])
type Func = Params => Option[String]

def isOneNull =
(b1 eq null) ^ (b2 eq null) option "b1 is null while b2 is not, vice versa"

def areSizesDifferent: Func = {
case (b1, b2) => b1.length != b2.length option "b1.length != b2.length"
}

def haveDifferentElements: Func = {
case (b1, b2) =>
(b1, b2).zipped.map(_ == _)
.zipWithIndex.find(!_._1)
.map { case (_, i) => "b1(%d) != b2(%d)" format (i, i) }
}

def areTheyDifferent =
Option(b1) <|*|> Option(b2) flatMap (
areSizesDifferent |@| haveDifferentElements
apply (_ orElse _)
) orElse isOneNull

areTheyDifferent foreach (msg => throw new AssertionError(msg))
}

Скала имеет неудачный издержки по сравнению с Хаскеллом, чтобы сделать эти вещи. Кроме того, Scalaz сможете сделать немного больше в следующей версии, но это работает с 6.0.

Выигрыш с Scalaz не является, однако, четкость и лаконичность (в этом коде, во всяком случае), но композиции. Например, в текущем Scalaz мы можем выделить всего тела areTheyDifferent такой:

def composeFM[M[_]:Plus, F[_]:Applicative, B](f: F[M[B]], g: F[M[B]]): F[M[B]] = 
(f |@| g)(_ <+> _)
type FAB[x] = Array[Byte] => x
def areTheyDifferent = (
Option(b1) <|*|> Option(b2)
flatMap composeFM[Option, FAB, Int](areSizesDifferent, haveDifferentElements)
orElse isOneNull
)

Обратите внимание, что composeFM не знает об опции или функции function1 - это относится к шаблону.

Ну, во всяком случае, сделайте ваш выбор. Иногда проблема просто не стоит, но полезно знать, как справиться в любом случае беда.

5
ответ дан 28 октября 2011 в 09:10 Источник Поделиться

Я не свободно в Scala, но массив-это просто тонкий слой на Java, поэтому список может быть чище.
В Java Массивы.равна(В1, В2) будет использоваться, чтобы делегировать на Java.

4
ответ дан 28 октября 2011 в 01:10 Источник Поделиться