Use array as case argument in switch

I am trying to do something like this, i.e. use an array in a switch statement. Is this possible in Java? If not, please explain a possible solution.

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; } 
+72
java arrays switch-statement
Dec 18 '13 at 13:50
source share
15 answers

NO , you just can't.

 SwitchStatement: switch ( Expression ) SwitchBlock 

The type of the expression must be char, byte, short, int, Character, Byte, Short, Integer, String or an enumeration type (Β§8.9), or a compile-time error occurs.

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

+60
Dec 18 '13 at 13:52
source share

@ sα΄œΚ€α΄‡sʜ α΄€α΄›α΄›α΄€ is right. But I wanted to add something. Starting with Java 7, switch statements support strings, so you can do something about it. This is really messy and I do not recommend, but it works:

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



For those who are concerned about performance: you are right, this is not very fast. This will compile something like this:

 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; } 
+72
Dec 18 '13 at 14:01
source share

You cannot include whole arrays. But you can convert to a bit set due to some readability of the switch itself:

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

and use binary literals in your cases: case 0b0101 is your first.

+50
Dec 18 '13 at 13:57
source share

Try this solution:

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

See the docs here .

+47
Dec 18 '13 at 13:53 on
source share

Yes, you can pass an array to the switch. The trick is that I'm not talking about Java arrays, but about the data structure.

An array is a systematic arrangement of objects, usually in rows and columns.

What you are trying to do is implement a system that recognizes different flags and depending on the flags that are on or off, you perform different actions.

Example

A popular implementation of this mechanism is access to Linux files. Where you have rwx as an "array of flags".

If the whole array is true, you will see rwx , which means that you have all permissions. If you are not allowed to perform any actions on the file, the entire array will be false, you will see --- .

Implementation

Guess what, you can think of integers as arrays. An integer is represented by an "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 

This is why rwx resolution can be represented as 7

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

To learn more about using binary format, check this question: In Java, can I define an integer constant in binary format?

Performance

  • Saves memory
  • You do not need to perform additional processing, switching, or any other type of juggling.

C programs that require the most efficient use of this type of mechanism; they use flags represented by single bits.

+21
Dec 18 '13 at 15:48
source share

No, you cannot, however you can replace the above code (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
Dec 18 '13 at 13:54
source share

If you are trying to determine if the set of conditions is true, I would use bit fields instead.

For example,

 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
Dec 18 '13 at 19:43
source share

I would calculate a value based on a sequence of elements in a boolean array, i.e. [true, false, true, true] will be evaluated to 1011, and then based on this integer value you can use the switch statement.

+6
Dec 18 '13 at 13:55
source share

The answer is NO. The best explanation is to learn how to use the switch statement .

+2
Dec 18 '13 at 13:52
source share

As in JRE 1.7, you will need to use a hack, I recommend:

  • Assume values.length <= 64

  • Convert values ​​to long representing bit flags

  • Switch vs hexadecimal magic numbers

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
Dec 20 '13 at 16:50
source share

Here is another approach that does not require imports and libraries:

 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
Dec 19 '13 at 13:16
source share

This answer is not Java, but Haxe, because it is possible as a result of pattern matching and has an interesting conclusion that may be useful for you to find a switch that does what you ask for. Arrays can be matched by a fixed length.

I created a demo that compiles in Javascript and Flash. You can see the js output in the right column.

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

This is a derived switch, it uses nested keys. If you play with these cases, you will see how js-ouput changes to an effective switch.

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

Another interesting model where you can use underscores. a_ pattern matches anything, so case _: is the default, which allows you to do this:

 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
Jan 07 '14 at 23:26
source share

You can also see how Groovy implements isCase () methods in Java, use a simpler version that suits your needs. You can put this in the interface and create a DSL to compare any two objects in your application.

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

The corresponding code is described in Line 877 through Lines 982

+1
Jan 14 '14 at 22:23
source share

@Todor Yes, THIS IS POSSIBLE 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; } 

Note. I'm not a Java developer, so my code syntax may be wrong, but the logic is perfect. You can edit my answer. Here I just tried to convert the array to string format and then combine in case of switch.

+1
Sep 02 '16 at 4:59
source share

I would use constant int values ​​that represent a boolean state.

If you use Java 1.7 or higher, you can use binary literals that are more readable .

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

for Java 1.6 and below use any other int literals, for example. hex

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

then create a method that converts the boolean array to an integer set of bits. For example.

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

Finally, use constants in the switch statement

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

Another approach could be to use java BitSet and Map , which maps to logic, which must be executed depending on the value of the bit set.

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

and realize your logic

 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
Apr 13 '16 at 12:03
source share



All Articles