Sử dụng một mảng làm câu lệnh trường hợp trong switch


76

Tôi đang cố gắng làm điều gì đó như thế này, tức là sử dụng một mảng trong câu lệnh switch. Nó có thể trong Java không? Nếu không, vui lòng giải thích một giải pháp khả thi.

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

5
Tôi nghĩ tốt nhất là sử dụng một câu lệnh if và tránh switch
Mukul Goel

56
Tôi nghĩ rằng bạn nên tự hỏi bản thân tại sao việc thực thi của bạn phải phụ thuộc vào một booleanmảng. Có lẽ một lớp có thể chứa dữ liệu này tốt hơn với các phương thức có nhiều ngữ nghĩa hơn (và dễ kiểm tra hơn)? Như bạn đã viết, nó giống như một cơn ác mộng bảo trì trong tương lai.
Eric Wilson

1
Sử dụng vòng lặp để đặt các bit trên một int dựa trên chỉ số mảng và tắt điều đó.
bát phân 9

15
Những gì bạn muốn được gọi là "khớp mẫu", nhưng bạn không thể làm điều đó trong Java.
Ingo

11
Có vẻ như bạn đang cố gắng để thực hiện cờ chút - xem câu hỏi này: Thực hiện một bitfield sử dụng enums java
T. Kiley

Câu trả lời:


65

KHÔNG , đơn giản là bạn không thể.

SwitchStatement:
    switch ( Expression ) SwitchBlock

Loại Biểu thức phải là char, byte, short, int, Character, Byte, Short, Integer, String hoặc kiểu enum (§8.9), nếu không sẽ xảy ra lỗi thời gian biên dịch.

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


Điều này đúng theo như tôi liên quan, mặc dù một số nỗ lực tốt trong các câu trả lời khác để có một giải pháp tốt.
Code Whisperer

8
Thành thật mà nói đây là câu trả lời tốt nhất. Tôi không chắc loại thể dục cần thiết để giải quyết vấn đề ban đầu nên được khuyến khích.
NotMe

Điều này thực sự cũ và tôi thậm chí không thể nhớ vấn đề ban đầu là gì, nhưng nhìn lại mã có vẻ như tôi đã thực hiện một số quyết định kiến ​​trúc tồi. Đây là lý do tại sao tôi nghĩ đây là câu trả lời chính xác - nó giống như một tín hiệu của việc làm sai điều gì đó hơn là tìm ra giải pháp.
Todor Grudev

74

@ sᴜʀᴇsʜ ᴀᴛᴛᴀ là đúng. Nhưng tôi muốn thêm một cái gì đó. Kể từ Java 7, các câu lệnh switch hỗ trợ Chuỗi, vì vậy bạn có thể làm gì đó với điều đó. Nó thực sự rất bẩn và tôi không khuyến khích, nhưng điều này hoạt động:

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

Đối với những người lo lắng về hiệu suất: bạn nói đúng, điều này không phải là quá nhanh. Điều này sẽ được biên dịch thành một cái gì đó như thế này:

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

Tôi khá trung lập + -1. Nó sẽ rất chậm. Ngoài ra, tôi không nghĩ rằng bạn phải phân tích cú pháp toString đầu ra theo bất kỳ cách nào.
Bathsheba

72
Sáng tạo và khủng khiếp cùng một lúc. +1
David

3
Quá hạn chế về kích thước của mảng, nếu mảng thay đổi về kích thước, thì việc duy trì sẽ thật là lộn xộn.
Jonathan Drapeau

1
Có thái độ blasé này đối với hiệu suất. Loại vấn đề này rất thường được giải quyết bằng cách đặt các bit trong một int- nhưng bạn chuyển đổi thành và so sánh các chuỗi . Trong Java .
bobobobo 19/1213

1
@bobobobo: Bạn nói đúng. Tôi sẽ không bao giờ viết điều này cho riêng tôi. Đây chỉ là một đoạn mã vui nhộn nằm rất gần với những gì OP muốn. Tôi biết rằng điều này thật kinh khủng, hãy tin tôi :)
Martijn Courteaux

50

Bạn không thể bật toàn bộ mảng. Nhưng bạn có thể chuyển đổi thành bộ bit với chi phí là khả năng đọc được của switchchính nó:

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

và sử dụng các ký tự nhị phân trong các câu lệnh trường hợp của bạn: case 0b0101là câu lệnh đầu tiên của bạn.


Wow, điều này chắc chắn là có thể, nhưng đó có phải là một giải pháp tốt cho vấn đề thực sự?
Eric Wilson

5
Để làm cho điều này có thể mở rộng, tôi sẽ đặt nó trong một vòng lặp: int switchVal = 0; for (int i = 0; i < values.length(); i++) { switchVal += values[i] ? (2 << i) : 0; }và sau đó bật switchValbiến.
Darrel Hoffman

3
Và để làm cho công tắc dễ đọc / có ý nghĩa hơn, hãy xem xét việc đặt mỗi ký tự nhị phân đó thành một hằng số có ý nghĩa để bạn đang chuyển đổi các hằng số, không phải các ký tự nhị phân.
rrauenza

3
Về cơ bản đây là chuyển đổi [true, false, true, false]thành chuỗi bit 1010, có thể được chỉnh sửa switch, phải không? Chắc chắn là cách để đi IMO.
Izkata

Tôi muốn hiển thị một ví dụ nhị phân sử dụng Lambda trong Java SE 8 nhưng không chắc liệu tôi có bị kích thích vì điều đó hay không. Tôi sẽ đợi cho đến tháng Ba.
ialexander

47

Hãy thử giải pháp này:

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

Xem tài liệu tại đây .


50
Đây là một giải pháp thực sự chặt chẽ về kích thước của mảng, thời điểm mảng thay đổi về kích thước, bạn sẽ gặp phải cơn ác mộng về bảo trì.
Jonathan Drapeau

98
Họ đặt tên cho một hàm isEquals??
Sebastian Mach

10
Không cần apache-commons-lang - chỉ cần sử dụng java.util.Arrays.equals(arr1,arr2)từ JDK.
Ed Staub

10
@drigoangelo: Tôi biết tôi biết. Nhưng tôi tự hỏi tại sao họ không chỉ sử dụng isEqual, vậy verb adjectivehoặc verb noun, thay vì verb verb. Cá nhân tôi chỉ thích adjectivecác hàm boolean và verbcác thủ tục thay đổi trạng thái.
Sebastian Mach


22

Có, bạn có thể chuyển một mảng cho một công tắc. Điều đáng chú ý là tôi không nói về mảng Java mà là cấu trúc dữ liệu.

Mảng là sự sắp xếp có hệ thống các đối tượng, thường là theo hàng và cột.

Những gì bạn đang cố gắng làm là triển khai một hệ thống nhận dạng các cờ khác nhau và tùy thuộc vào các cờ được bật hoặc tắt mà bạn thực hiện các hành động khác nhau.

Thí dụ

Một cách thực hiện phổ biến của cơ chế này là quyền đối với tệp Linux. Nơi bạn có rwxlà "mảng cờ".

Nếu toàn bộ mảng là true, bạn sẽ thấy rwx, điều đó có nghĩa là bạn có tất cả các quyền. Nếu bạn không được phép thực hiện bất kỳ hành động nào trên tệp, thì toàn bộ mảng là sai, bạn sẽ thấy ---.

Thực hiện

Đoán xem, bạn có thể coi số nguyên là mảng. Một số nguyên được biểu diễn bằng một "mảng các bit".

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

Đó là lý do tại sao quyền rwxcó thể được biểu diễn dưới dạng7

Đoạn mã 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");           
        }                                                                        
    }                                                                            
}

Để biết thêm về cách sử dụng định dạng nhị phân, hãy kiểm tra câu hỏi này: Trong Java, tôi có thể xác định một hằng số nguyên ở định dạng nhị phân không?

Hiệu suất

  • Tiết kiệm bộ nhớ
  • Bạn không cần phải xử lý thêm, chuyển đổi hoặc bất kỳ loại tung hứng nào khác.

C các chương trình đòi hỏi phải hiệu quả nhất có thể sử dụng loại cơ chế này; họ sử dụng cờ được biểu diễn bằng các bit đơn.


21

Không, bạn không thể, tuy nhiên bạn có thể thay thế ở trên bằng mã sau (tôi thừa nhận):

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

3
Tôi sẽ đặt công thức tổng vào một phương thức thay vì trực tiếp trong switchcâu lệnh.
Jonathan Drapeau

8
Ngoài thực tế là nó là errr xấu xí nó là sai: 0010được hiểu như là bát phân ...
Gyro cơ không hộp số

2
Phương thức trợ giúp @Alex nên là private;) Ngoài ra, nó không phải là một ý tưởng tốt return intvì đối với các mảng lớn, điều này có thể tràn.
Maroun

1
Tôi như thế này, trong nhiều như nó có vẻ như nó sẽ được dễ dàng hơn để duy trì vs khổng lồ nếu / else trong câu trả lời được chấp nhận
WernerCD

1
Ngoài ra, tại sao (values[0]?1:0)*1000nếu bạn có thể làm values[0]?1000:0?
Cruncher

10

Nếu bạn đang cố gắng xác định xem một tập hợp các điều kiện có đúng không, tôi sẽ sử dụng các trường bitwise thay thế.

Ví dụ,

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

6

Tôi sẽ tính toán một giá trị dựa trên trình tự của các phần tử trong mảng boolean, tức là [true, false, true, true]sẽ đánh giá đến 1011 và sau đó dựa trên giá trị số nguyên này, bạn có thể sử dụng câu lệnh switch.


Đảm bảo rằng nếu bạn thay đổi độ dài (hoặc thứ tự) của mảng, thì mảng đó vẫn hoạt động, nếu bạn muốn tránh việc viết lại mọi câu lệnh 'case'. Nếu Java không cho phép gọi hàm cho mỗi 'trường hợp', một chuỗi if lớn sẽ được yêu cầu, có thể với một mảng kết hợp cho mỗi trường hợp thay thế và một lệnh gọi hàm cho mỗi lần kiểm tra if.
Phil Perry

2

Câu trả lời là không. Cách giải thích tốt nhất là học cách sử dụng câu lệnh switch .


Các câu lệnh switch chỉ nhận các kiểu ints, chars, byte, short và enum. Cách "đúng đắn" để làm điều đó sẽ là một khối if..else lớn hoặc bằng cách nào đó kết xuất mảng boolean xuống thành một số nguyên và hành động tương ứng. Có thể coi nó như một bitmask?
David

1
Java cũng switch mất chuỗi
Bathsheba

2
@Bathsheba Đối với Java7 +.
Maroun

2

Đối với JRE 1.7, bạn sẽ cần phải sử dụng một bản hack, tôi khuyên bạn nên:

  • Giả định values.length <= 64

  • Chuyển đổi giá trị thành longbitflags đại diện

  • Switchchống lại số ma thuật thập lục phân

Hack mã 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

Câu trả lời này không phảiJava , mà là Haxe bởi vì nó có thể có trong đó, nhờ khớp mẫu và có đầu ra thú vị, có thể hữu ích cho bạn để tìm một công tắc phù hợp với những gì bạn đang yêu cầu. Mảng có thể được khớp với chiều dài cố định.

Tôi đã tạo một bản trình diễn biên dịch sang Javascript và Flash. Bạn có thể thấy js-output ở cột bên phải.

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

Đây là công tắc đầu ra, nó sử dụng các công tắc lồng nhau. Nếu bạn chơi với các trường hợp, bạn sẽ thấy js-ouput thay đổi như thế nào để có một công tắc hiệu quả.

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

Một mẫu thú vị khác mà bạn có thể sử dụng dấu gạch dưới. một mẫu _ khớp với bất kỳ thứ gì, vì vậy trường hợp _: bằng mặc định, giúp bạn có thể thực hiện việc này:

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

Đây là một cách tiếp cận khác không yêu cầu nhập hoặc không có thư viện:

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

Bạn cũng có thể xem cách Groovy triển khai các phương thức isCase () trong Java, sử dụng phiên bản đơn giản hơn phù hợp với nhu cầu của bạn. Có thể đặt nó trong một giao diện và tạo một DSL để so sánh hai đối tượng bất kỳ trong ứng dụng của bạn.

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

Mã liên quan được đề cập trong các Dòng 877 đến các Dòng 982


1

@Todor Có, ĐIỀU NÀY CÓ THỂ TRONG 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;
}

Lưu ý: Tôi không phải là nhà phát triển java, vì vậy cú pháp mã của tôi có thể sai, nhưng logic thì hoàn hảo. Bạn có thể chỉnh sửa câu trả lời của tôi. Ở đây tôi chỉ cố gắng chuyển đổi mảng sang định dạng chuỗi và sau đó khớp trong trường hợp chuyển đổi.


0

Tôi sẽ sử dụng các giá trị int hằng số đại diện cho trạng thái boolean.

Nếu bạn sử dụng Java 1.7 trở lên, bạn có thể sử dụng các ký tự nhị phân dễ đọc hơn .

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

đối với Java 1.6 trở xuống sử dụng bất kỳ ký tự int nào khác, ví dụ: hex

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

sau đó tạo một phương thức chuyển đổi một mảng boolean thành một tập bit số nguyên. Ví dụ

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

Cuối cùng sử dụng các hằng số trong câu lệnh switch của bạn

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

Một cách tiếp cận khác có thể là sử dụng java BitSetvà một Mapánh xạ tới logic sẽ được thực thi tùy thuộc vào giá trị của bitet.

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

và thực hiện logic của bạn

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

}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.