Usar um array como uma instrução de caso na mudança

eu estou tentando fazer algo assim, isto é, usar um array em uma declaração de switch. É possível em Java? Se não for, por favor explique uma solução possível.

boolean[] values = new boolean[4];

values[0] = true;
values[1] = false;
values[2] = false;
values[3] = true;

switch (values) {
    case [true, false, true, false]:
        break;
    case [false, false, true, false]:
        break;
    default:
        break;
}
Author: Joel, 2013-12-18

15 answers

Não, simplesmente não podes.

SwitchStatement:
    switch ( Expression ) SwitchBlock

O tipo da expressão deve ser char, byte, short, int, Character, Byte, Short, Integer, String, or an enum type (§8.9), or a compile-time error occurs.

Http://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.11

 63
Author: ꜱᴜʀᴇꜱʜ ᴀᴛᴛᴀ, 2013-12-18 13:52:48

@sᴜʀᴇsʜ ᴀᴛᴛᴀ está certo. Mas queria acrescentar uma coisa. Desde o Java 7, switch declarações suporta Strings, então você pode fazer algo com isso. é realmente sujo e eu não recomendo, mas isto funciona:

boolean[] values = new boolean[4];

values[0] = true;
values[1] = false;
values[2] = false;
values[3] = true;

switch (Arrays.toString(values)) {
    case "[true, false, true, false]":
        break;
    case "[false, false, true, false]":
        break;
    default:
        break;
}

Para aqueles preocupados com o desempenho: você está certo, isto não é super rápido. Isto será compilado em algo assim:

String temp = Arrays.toString(values)
int hash = temp.hashCode();
switch (hash)
{
    case 0x23fe8da: // Assume this is the hashCode for that
                    // original string, computed at compile-time
        if (temp.equals("[true, false, true, false]"))
        {

        }
        break;
    case 0x281ddaa:
        if (temp.equals("[false, false, true, false]"))
        {

        }
        break;

    default: break;
}
 73
Author: Martijn Courteaux, 2013-12-18 14:12:34
Não se pode ligar conjuntos inteiros. Mas você poderia converter para um pouco definido à custa de alguma legibilidade do próprio switch:

switch (values[0] + 2 * values[1] + 4 * values[2] + 8 * values[3])

E usar literais binários nas suas declarações de caso: case 0b0101 é o seu primeiro.

 50
Author: Bathsheba, 2013-12-18 14:03:20

Tenta esta solução:

    boolean[] values = new boolean[4];
    values[0] = true;
    values[1] = false;
    values[2] = false;
    values[3] = true;

    if (ArrayUtils.isEquals(values, new boolean[] {true, false, true, false})) {
    ...
    }
    else if (ArrayUtils.isEquals(values, new boolean[] {false, false, true, false})) {
    ...
    }
    else {
    ...
    }

Ver docsaqui .

 47
Author: Alex, 2013-12-18 13:53:16
Sim, pode passar uma matriz para um interruptor. O problema é que não estou a falar de conjuntos Java, mas de uma estrutura de dados.

Um array é um arranjo sistemático de objetos, geralmente em linhas e Colunas.

O que você está tentando fazer é implementar um sistema que reconhece diferentes bandeiras e dependendo das bandeiras que estão ligadas ou desligadas você toma diferentes ações.

Exemplo

Uma implementação popular desse mecanismo é o Linux. permissões de ficheiros. Onde você tem rwx como o "array of flags".

Se toda a matriz for verdadeira, você verá {[[2]}, o que significa que você tem todas as permissões. Se você não estiver autorizado a realizar qualquer ação em um arquivo, todo o array é falso, você verá ---.

Execução

Adivinha, podes pensar em inteiros como conjuntos. Um inteiro é representado por um"array of bits".
001 // 1, if on, set x 
010 // 2, if on, set w 
100 // 4, if on, set r
// putting it all together in a single "array" (integer)
111 // 2^2 + 2^1 + 2^0 = 4 + 2 + 1 = 7
É por isso que a permissão rwx pode ser representada como um 7

Excerto de Java:

class Flags {                                                                    
public static void main(String args[]) {         
        /** 
         * Note the notation "0b", for binary; I'm using it for emphasis.
         * You could just do: 
         * byte flags = 6;
         */                     
        byte flags = 0b110; // 6                     
        switch(flags) {                                                          
            case 0: /* do nothing */ break;                                      
            case 3: /* execute and write */ break;                       
            case 6: System.out.println("read and write\n"); break;         
            case 7: /* grant all permissions */ break;                           
            default:                                                             
                System.out.println("invalid flag\n");           
        }                                                                        
    }                                                                            
}

Para saber mais sobre a utilização de um formato binário, assinale esta pergunta: em Java, posso definir uma constante de inteiro no formato binário?

Desempenho

  • Guarda memória
  • Você não tem que fazer processamento extra, interruptores ou qualquer outro tipo de malabarismo.

Os programas C que necessitam de ser tão eficientes quanto possível usam este tipo de mecanismo; eles usam bandeiras representadas com bits simples.

 21
Author: givanse, 2017-05-23 12:10:36

Não, você não pode, no entanto você pode substituir o acima com o seguinte código (dirty I admit):

boolean[] values = new boolean[4];

values[0] = true;
values[1] = false;
values[2] = false;
values[3] = true;

switch(makeSuitableForSwitch(values)) {
   case 1010: 
     break;
   case 10: 
     break;
   default:
     break;
} 

private int makeSuitableForSwitch( boolean[] values) {
    return (values[0]?1:0)*1000+(values[1]?1:0)*100+(values[2]?1:0)*10+(values[3]?1:0);
}
 20
Author: Adam Siemion, 2014-10-01 16:56:39

Se está a tentar determinar se um conjunto de condições é verdadeiro, eu usaria campos bitwise em vez disso.

Por exemplo,

public class HelloWorld
{
  // These are the options that can be set.
  // They're final so treated as constants.
  static final int A=1<<0, B=1<<1, C=1<<2, D=1<<3 ;

  public static void main(String []args)
  {
    // Now I set my options to have A=true, B=true, C=true, D=false, effectively
    int options = A | B | C ;

    switch( options )
    {
      case (A):
        System.out.println( "just A" ) ;
        break ;
      case (A|B):
        System.out.println( "A|B" ) ;
        break ;
      case (A|B|C): // Final int is what makes this work
        System.out.println( "A|B|C" ) ;
        break ;
      default:
        System.out.println( "unhandled case" ) ;
        break ;
    }
  }
}
 9
Author: bobobobo, 2013-12-18 19:43:12

Eu calcularia um valor baseado na sequência dos elementos na matriz booleana, ou seja [true, false, true, true] iria avaliar para 1011 e então com base neste valor inteiro você pode usar a declaração de switch.

 6
Author: Juvanis, 2013-12-18 13:55:56
A resposta é não. A melhor explicação é aprender a usar a declaração de switch .
 2
Author: Sergi, 2013-12-18 13:52:44

A partir de JRE 1.7, você vai precisar de usar um hack, eu recomendo:

  • Assumir values.length <= 64

  • Converter os valores para um long representando bitflags

  • Switch contra os números mágicos hexadecimal

Hack De Código Java:

if(values.length > 64)
  throw new IllegalStateException();

long bitflags = 0x0L;

for(int i=0; i< values.length; ++i)
  if(values[i])
    bitflags |= 0x01L << i;

switch(bitflags) {
  case 0xEL: // represents [true,  true,  true, false]
    break;
  case 0xAL: // represents [true,  false, true, false]
    break;
  case 0x2L: // represents [false, false, true, false]
    break;
  default:
    break;
}
 2
Author: recursion.ninja, 2013-12-20 16:50:05
Aqui está uma outra abordagem que não requer importações nem bibliotecas:
boolean[] values = new boolean[4];

values[0] = true;
values[1] = false;
values[2] = false;
values[3] = true;

int mask = buildMask(values);

if (areEquals(mask, true, false, true, false)) {
    // ...
} else if (areEquals(mask, false, false, true, false)) {
    // ...
} else {
    // ...
}

private int buildMask(boolean... values) {
    int n = 0;
    for (boolean b : values) {
        n = (n << 1) | (b ? 1 : 0);
    }
    return n;
}

private boolean areEquals(int mask, boolean... values) {
    return mask == buildMask(values);
}
 1
Author: Stephan, 2013-12-19 13:16:31

Esta resposta não é Java , mas Haxe porque é possível nela, graças à correspondência de padrões e tem uma saída interessante, o que pode ser útil para você encontrar um interruptor que faça o que você está pedindo. Arrays podem ser combinados em comprimento fixo.

Criei uma demo que compila Javascript e Flash. Você pode ver o js-output na coluna direita.

Demo: http://try.haxe.org/#86314

class Test {
  static function main(){

    var array=[true,false,true];

    var result=switch(array){
      case [true,true,false]: "no";
      case [true,false,true]: "yes";
      default:"??";
    }

    #if js
      new js.JQuery("body").html(result);
    #elseif flash
      trace(result);
    #end

    // ouputs: "yes"
  }
}
Este é o ... Interruptor avançado, usa interruptores aninhados. Se você jogar com os casos, você vê como o js-ouput muda para ter um interruptor eficiente.
(function () { "use strict";
var Test = function() { };
Test.main = function() {
    var array = [true,false,true,false];
    var result;
    switch(array.length) {
    case 4:
        switch(array[0]) {
        case true:
            switch(array[1]) {
            case false:
                switch(array[2]) {
                case true:
                    switch(array[3]) {
                    case false:
                        result = "no";
                        break;
                    default:
                        result = "??";
                    }
                    break;
                default:
                    result = "??";
                }
                break;
            default:
                result = "??";
            }
            break;
        case false:
            switch(array[1]) {
            case false:
                switch(array[2]) {
                case true:
                    switch(array[3]) {
                    case false:
                        result = "yes";
                        break;
                    default:
                        result = "??";
                    }
                    break;
                default:
                    result = "??";
                }
                break;
            default:
                result = "??";
            }
            break;
        }
        break;
    default:
        result = "??";
    }
    new js.JQuery("body").html(result);
};
var js = {};
var q = window.jQuery;
js.JQuery = q;
Test.main();
})();

Outro padrão interessante que pode usar sobscores. um _ padrão corresponde a qualquer coisa, por isso o caso _: é igual ao padrão, o que o torna capaz de fazer isto:

var myArray = [1, 6];
var match = switch(myArray) {
    case [2, _]: "0";
    case [_, 6]: "1";
    case []: "2";
    case [_, _, _]: "3";
    case _: "4";
}
trace(match); // 1

Http://haxe.org/manual/pattern_matching#array-matching

 1
Author: Mark Knol, 2014-01-07 23:26:10

Você também pode dar uma olhada em como Groovy implementa os métodos isCase () em Java, usar uma versão mais simples que se encaixa às suas necessidades. É possível colocar isso em uma interface e criar um DSL para comparar qualquer dois objetos em sua aplicação.

return isCase(DefaultTypeTransformation.asCollection(caseValue), switchValue);

O código relevante é coberto pelas linhas das linhas 877 até . 982

 1
Author: rgamed, 2014-01-14 22:23:13

@Todor Sim, isto é possível em JAVA.

boolean[] values = new boolean[4];

values[0] = true;
values[1] = false;
values[2] = false;
values[3] = true;

values = Arrays.toString(values)

switch (values) {
    case "[true, false, true, false]":
        break;
    case "[false, false, true, false]":
        break;
    case "[true, false, false, true]":
        System.out.println("YAAAAAAAAAA GOT IT");
        break;
    default:
        break;
}

Nota: não sou um programador java, por isso a minha sintaxe de código pode estar errada, mas a lógica é perfeita. Podes editar a minha resposta. Aqui Eu apenas tentei converter array para o formato string e, em seguida, corresponder no caso switch.

 1
Author: jatin, 2016-09-02 04:59:23
Eu usaria valores int constantes que representam o estado booleano.

Se usar Java 1, 7 ou acima, poderá usar literais binários que sejam mais legíveis.

public static final int TRUE_FALSE_TRUE_FALSE = 0b1010;
public static final int FALSE_FALSE_TRUE_FALSE = 0b0010;

Para Java 1.6 e abaixo usar qualquer outro int literais, por exemplo hex

public static final int TRUE_FALSE_TRUE_FALSE = 0xA;
public static final int FALSE_FALSE_TRUE_FALSE = 0x2;

Em seguida, criar um método que converte um array booleano para um conjunto de bits inteiro. Por exemplo

public static int toIntBitSet(boolean...values){
    int bitset = 0;
    for (boolean value : values) {
       bitset = (bitset << 1) | (value ? 1 : 0);
    }
    return bitset;
}

Finalmente use as constantes na sua declaração de mudança

boolean[] values = new boolean[]{true, false, true, false};

int bitset = toIntBitSet(values);

switch (bitset) {
  case TRUE_FALSE_TRUE_FALSE:
    System.out.println(Integer.toBinaryString(bitset));
    break;
  case FALSE_FALSE_TRUE_FALSE:
    System.out.println(Integer.toBinaryString(bitset));
    break;
  default:
    break;
}

Outro approach May Be to use a java BitSet and a Map that maps to the logic that should be executed depending on the bitset value.

public static void main(String[] args) throws Exception {
  Map<BitSet, Callable<String>> bitSetMap = new HashMap<>();

  bitSetMap.put(bitSetValueOf(true, false, true, false), new TrueFalseTrueFalseCallable());
  bitSetMap.put(bitSetValueOf(false, false, true, false), new FalseFalseTrueFalseCallable());

  boolean[] values = new boolean[]{true, false, true, false};

  BitSet bitset = bitSetValueOf(values);

  Callable<String> callable = bitSetMap.get(bitset);
  if (callable == null) {
    callable = new DefaultCallable();
  }

  String result = callable.call();
  System.out.println(result);
}

public static BitSet bitSetValueOf(boolean... values) {
   BitSet bitSet = new BitSet();
      for (int i = 0; i < values.length; i++) {
         bitSet.set(i, values[i]);
      }
   return bitSet;
}

E implementar a sua lógica

class FalseFalseTrueFalseCallable implements Callable<String> {

  @Override
  public String call() throws Exception {
    return "0010";
  }

}

class TrueFalseTrueFalseCallable implements Callable<String> {

  @Override
  public String call() throws Exception {
    return "1010";
  }

}

class DefaultCallable implements Callable<String> {

  @Override
  public String call() throws Exception {
    return "default value";
  }

}
 0
Author: René Link, 2016-04-13 12:32:32