web-dev-qa-db-ger.com

Verwenden Sie ein Array als case-Anweisung in switch

Ich versuche so etwas zu tun, d. H. Ein Array in einer switch-Anweisung zu verwenden. Ist es in Java möglich? Ist dies nicht der Fall, erläutern Sie bitte eine mögliche Lösung.

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;
}
73
Todor Grudev

NEIN, das geht einfach nicht.

SwitchStatement:
    switch ( Expression ) SwitchBlock

Der Typ des Ausdrucks muss char, Byte, short, int, Character, Byte, short, Integer, String oder ein Aufzählungstyp (§8.9) sein. Andernfalls tritt ein Fehler beim Kompilieren auf. 

http://docs.Oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.11

62
Suresh Atta

@ sᴜʀᴇsʜ ᴀᴛᴛᴀ ist richtig. Aber ich wollte etwas hinzufügen. Seit Java 7 unterstützen switch-Anweisungen Strings, damit könnte man etwas unternehmen. Es ist wirklich schmutzig und ich empfehle es nicht, aber das funktioniert:

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

Für diejenigen, die sich Gedanken über die Leistung machen: Sie haben Recht, das ist nicht besonders schnell. Dies wird wie folgt kompiliert:

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

Sie können nicht ganze Arrays einschalten. Aber Sie könnten auf Kosten der Lesbarkeit von switch selbst in ein gesetztes Bit konvertieren:

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

und benutze binäre Literale in deinen case-Anweisungen: case 0b0101 ist dein erster.

50
Bathsheba

Versuchen Sie diese Lösung:

    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 {
    ...
    }

Siehe docs hier .

47
Alex

Ja, Sie können ein Array an einen Switch übergeben. Der Haken ist, dass es nicht um Java-Arrays geht, sondern um eine Datenstruktur.

Ein Array ist eine systematische Anordnung von Objekten, normalerweise in Zeilen und Spalten.

Sie möchten ein System implementieren, das verschiedene Flags erkennt, und je nach aktivierten oder deaktivierten Flags führen Sie verschiedene Aktionen aus.

Beispiel

Eine beliebte Implementierung eines solchen Mechanismus sind Linux-Dateiberechtigungen. Wo haben Sie rwx als "Array von Flags". 

Wenn das gesamte Array true ist, wird rwx angezeigt, dh Sie verfügen über alle Berechtigungen. Wenn Sie keine Aktion für eine Datei ausführen dürfen, ist das gesamte Array "false" und es wird --- angezeigt.

Implementierung

Weißt du was, du kannst ganze Zahlen als Arrays sehen. Eine ganze Zahl wird durch ein "Array von Bits" dargestellt.

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

Aus diesem Grund kann die Berechtigung rwx als 7 dargestellt werden.

Java-Snippet:

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

Um mehr über die Verwendung eines Binärformats zu erfahren, überprüfen Sie diese Frage: Kann ich in Java eine Ganzzahlkonstante im Binärformat definieren?

Leistung

  • Speichert den Speicher
  • Sie müssen keine zusätzlichen Verarbeitungsschritte, Schalter oder andere Arten von Jonglieren durchführen.

C-Programme, die so effizient wie möglich sein müssen, verwenden diesen Mechanismus. Sie verwenden Flags, die mit einzelnen Bits dargestellt werden.

21
givanse

Nein, das ist nicht möglich. Sie können den obigen Code jedoch durch folgenden Code ersetzen:

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
Adam Siemion

Wenn Sie feststellen wollen, ob ein Satz von Bedingungen wahr ist, würde ich stattdessen bitweise Felder verwenden.

Zum Beispiel,

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
bobobobo

Ich würde einen Wert basierend auf der Reihenfolge der Elemente im booleschen Array berechnen, d. H. [true, false, true, true] würde den Wert 1011 auswerten, und basierend auf diesem Integerwert können Sie die switch-Anweisung verwenden.

6
Juvanis

Die Antwort ist nein. Die beste Erklärung ist, wie man die switch-Anweisung verwendet.

2
Sergi

Ab JRE 1.7 müssen Sie einen Hack verwenden. Ich empfehle:

  • values.length <= 64 annehmen 

  • Konvertieren Sie Werte in eine long, die Bitflags darstellt

  • Switch gegen hexadezimal magische Zahlen

Java Code Hack:

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
recursion.ninja

Hier ist ein anderer Ansatz, der weder Import noch Bibliotheken erfordert:

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
Stephan

Diese Antwort ist nicht Java, aber Haxe, weil es dank Pattern Matching möglich ist und interessante Ausgaben bietet, die für Sie nützlich sein könnten, um einen Switch zu finden, der das tut, was Sie wünschen. Arrays können auf fester Länge abgeglichen werden.

Ich habe eine Demo erstellt, die zu Javascript und Flash kompiliert wird. Die js-Ausgabe sehen Sie in der rechten Spalte. 

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

Dies ist der ausgegebene Schalter, er verwendet verschachtelte Schalter. Wenn Sie mit den Fällen spielen, sehen Sie, wie sich das js-outout ändert, um einen effizienten Switch zu erhalten.

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

Ein weiteres interessantes Muster, das Sie Unterstriche verwenden können. Ein _-Muster stimmt mit irgendetwas überein, daher ist Fall _: gleich default, wodurch Sie Folgendes tun können:

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
Mark Knol

@Todor Ja, DIESES IS MÖGLICH IN 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;
}

Hinweis: Ich bin kein Java-Entwickler, daher kann meine Codesyntax falsch sein. Die Logik ist jedoch perfekt. Sie können meine Antwort bearbeiten. Hier habe ich gerade versucht, das Array in ein String-Format zu konvertieren und dann im Switch-Case zu finden.

1
jatin

Sie können auch einen Blick darauf werfen, wie Groovy die isCase () - Methoden in Java implementiert. Verwenden Sie eine einfachere Version, die Ihren Anforderungen entspricht. Es ist möglich, dies in eine Schnittstelle einzufügen und ein DSL zu erstellen, um zwei beliebige Objekte in Ihrer Anwendung zu vergleichen.

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

Der entsprechende Code wird in Zeilen 877 bis Zeilen 982 behandelt.

1
rgamed

Ich würde konstante int-Werte verwenden, die den booleschen Zustand darstellen.

Wenn Sie Java 1.7 oder höher verwenden, können Sie binäre Literale verwenden, die lesbarer sind.

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

für Java 1.6 und darunter alle anderen Int-Literale verwenden, z. verhexen 

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

erstellen Sie dann eine Methode, die ein boolesches Array in ein ganzzahliges Bitset konvertiert. Z.B.

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

Verwenden Sie schließlich die Konstanten in Ihrer switch-Anweisung

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

Ein anderer Ansatz könnte die Verwendung von Java BitSet und Map sein, die der Logik zugeordnet sind, die abhängig vom Wert des Bitsets ausgeführt werden soll.

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

und implementiere deine Logik

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
René Link