Как вы проходите через каждый статус в Scala?

Я пытаюсь перебрать каждое состояние, чтобы проверить, имеет ли ArrayList хотя бы 1 статус ACTIVE и 1 статус INACTIVE.

var active = false;
var inactive = false;
for (item <- reasons.items) {
  if(item.status == "ACTIVE")
    active = true
  if(item.status == "INACTIVE")
    }
active must be (true)
inactive must be (true)

Есть ли более чистый способ сделать это? Я пробовал с такими потоками, но не повезло

var active = false;      
var stream = reasons.items.toStream
        .forEach(item => if(item.status == "ACTIVE") {active = true})

Примечание: причины удерживает предметы (Есть 1 предметов). items содержит отдельные элементы, которые могут быть вызваны как reason.items.get(x).

3 ответа

Решение

Другие ответы хорошо объясняют, как этого добиться, используя коллекции Scala. Поскольку похоже, что вы используете ScalaTest, я хотел бы добавить, что вы также можете использовать ScalaTest для циклического перемещения по элементам.

Использование синтаксиса в стиле цикла от инспекторов:

forAtLeast(1, reasons.items) { item =>
  item.status must be ("ACTIVE")
}

forAtLeast(1, reasons.items) { item =>
  item.status must be ("INACTIVE")
}

Обратите внимание, что инспекторы определяются отдельно от сопоставителей, поэтому вам придется import org.scalatest.Inspectors._ или же extends … with org.scalatest.Inspectors получить forAtLeast в сферу.

Если вы хотите избежать синтаксиса стиля цикла от инспекторов, вы можете использовать сокращенный синтаксис инспектора вместе с основанным на отражении have синтаксис:

atLeast(1, reasons.items) must have ('status "ACTIVE")
atLeast(1, reasons.items) must have ('status "INACTIVE")

Если вы хотите избежать основанного на отражении синтаксиса для haveВы можете продлить have синтаксис для поддержки вашего status собственность напрямую:

def status(expectedValue: String) =
  new HavePropertyMatcher[Item, String] {
    def apply(item: Item) =
      HavePropertyMatchResult(
        item.status == expectedValue,
        "status",
        expectedValue,
        item.title
      )
  }

atLeast(1, reasons.items) must have (status "ACTIVE")
atLeast(1, reasons.items) must have (status "INACTIVE")

Или, если вы предпочитаете be над haveВы могли бы продлить be синтаксис для добавления поддержки active а также inactive:

class StatusMatcher(expectedValue: String) extends BeMatcher[Item] {
  def apply(left: Item) =
    MatchResult(
      left.status == expectedValue,
      left.toString + " did not have status " + expectedValue,
      left.toString + " had status " + expectedValue,
    )
}

val active = new StatusMatcher("ACTIVE")
val inactive = new statusMatcher("INACTIVE")

atLeast(1, reasons.items) must be (active)
atLeast(1, reasons.items) must be (inactive)

В примерах, приведенных здесь, выглядит немного глупо определять собственные сопоставители, чтобы сохранить пару слов в утверждении, но если вы напишите сотни тестов об одних и тех же свойствах, может быть очень удобно свести утверждения к одной строке и все еще быть естественно читаемым. Таким образом, по моему опыту, определение таких собственных сопоставителей может иметь смысл, если вы повторно используете их во многих тестах.

Для "по крайней мере 1" вы можете использовать exists на items который проверяет заданный предикат и возвращает истину, если хотя бы один из элементов удовлетворяет критериям. Для "АКТИВНЫЙ и НЕАКТИВНЫЙ" вы можете объединить два exists требует неэффективного подхода с использованием &&.

reasons.items.exists(_.status.equals("ACTIVE")) && reasons.items.exists(_.status.equals("INACTIVE"))`

Чистый подход будет

val active = reasons.items.exists(item => item.status == "ACTIVE")

или короче

val active = reasons.items.exists(_.status == "ACTIVE")

Аналогично для val inactive, Это имеет проблему итерации по списку дважды (но остановка, как только подходящий элемент найден оба раза в отличие от вашего кода).

Другие вопросы по тегам