在 Java 中填充布尔数组
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24651403/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Populating a Boolean Array in Java
提问by lordchancellor
As a fairly green Java coder I've set myself the hefty challenge of trying to write a simple text adventure. Unsurprisingly, I've encountered difficulties already!
作为一名相当绿色的 Java 编码员,我为自己设定了尝试编写简单文本冒险的巨大挑战。不出所料,我已经遇到了困难!
I'm trying to give my Location class a property to store which exits it contains. I've used a boolean array for this, to essentially hold true/false values representing each exit. I'm not entirely convinced that
我试图给我的 Location 类一个属性来存储它包含的退出。我为此使用了一个布尔数组,基本上保存代表每个出口的真/假值。我不完全相信
a)this is the most efficient way to do this and
a)这是最有效的方法,并且
b)that I'm using the right code to populate the array.
b)我正在使用正确的代码来填充数组。
I would appreciate any and all feedback, even if it is for a complete code over-haul!
我会很感激任何和所有的反馈,即使它是一个完整的代码大修!
At present, when instantiating a Location I generate a String which I send through to the setExits method:
目前,当实例化一个位置时,我生成一个字符串,我将它发送到 setExits 方法:
String e = "N S U";
secretRoom.setExits(e);
In the Location class, setExits looks like this:
在 Location 类中, setExits 如下所示:
public void setExits(String e) {
if (e.contains("N"))
bexits[0] = true;
else if (e.contains("W"))
bexits[1] = true;
else if (e.contains("S"))
bexits[2] = true;
else if (e.contains("E"))
bexits[3] = true;
else if (e.contains("U"))
bexits[4] = true;
else if (e.contains("D"))
bexits[5] = true;
}
I'll be honest, I think this looks particularly clunky, but I couldn't think of another way to do it. I'm also not entirely sure now how to write the getExits method...
老实说,我认为这看起来特别笨拙,但我想不出其他方法来做到这一点。我现在也不完全确定如何编写 getExits 方法......
Any help would be welcome!
欢迎任何帮助!
采纳答案by Ross Drew
Is there any reason why you are doing this with String
s and aren't passing in booleans
, i.e.
有什么理由让你用String
s做这件事并且没有传入booleans
,即
public void setExits(boolean N, boolean E, boolean S, boolean W, boolean U, boolean D)
Or having setters?
或者有二传手?
public void setNorthOpen(boolean open)
{
bexits[4] = open;
}
Secondly, why are you storing the exits as an array of booleans, it's a small finite set, why not just
其次,为什么要将出口存储为布尔数组,它是一个小的有限集,为什么不只是
boolean N,S,E,W,U,D;
As then you don't need to keep track of which number in the array each direction is.
那样你就不需要跟踪每个方向是数组中的哪个数字。
Also
还
This is a correct answer (if not completely optimal like that of @gexicide) but I fully encourage anyone to look at the other answers here for an interesting look at how things can be done in Java in different ways.
这是一个正确的答案(如果不是像@gexicide 那样完全最佳),但我完全鼓励任何人查看这里的其他答案,以有趣的方式了解如何以不同的方式在 Java 中完成工作。
For future reference
备查
Code which works belongs on Code Review, not Stack Overflow. Although as @kajacx pointed out, this code shouldn't -in fact- work.
有效的代码属于Code Review,而不是 Stack Overflow。尽管正如@kajacx 指出的那样,这段代码实际上不应该工作。
回答by Pphoenix
If you want a generic solution you can use a map, which maps from a key (in your case W, S, E.. ) to a corresponding value (in your case a boolean).
如果你想要一个通用的解决方案,你可以使用map,它从一个键(在你的情况下 W, S, E.. )映射到一个相应的值(在你的情况下是一个布尔值)。
When you do a set
, you update the value the key is associated with. When you do a get
, you can take an argument key and simply retrieve the value of the key. This functionality does already exist in map, called putand get.
执行 a 时set
,会更新与键关联的值。当您执行 a 时get
,您可以使用参数键并简单地检索键的值。这个功能已经存在于 map 中,称为put和get。
回答by niekname
I would create an Exit enum and on the location class just set a list of Exit objects.
我会创建一个 Exit 枚举,并在 location 类上设置一个 Exit 对象列表。
so it would be something like:
所以它会是这样的:
public enum Exit { N, S, E, W, U, D }
List<Exit> exits = parseExits(String exitString);
location.setExits(exits);
回答by T.G
If you're defining exits as a string, you should use it. I would do it like:
如果您将出口定义为字符串,则应该使用它。我会这样做:
public class LocationWithExits {
public static final String NORTH_EXIT="[N]";
public static final String SOUTH_EXIT="[S]";
public static final String EAST_EXIT="[E]";
public static final String WEST_EXIT="[W]";
private final String exitLocations;
public LocationWithExits(String exitLocations) {
this.exitLocations = exitLocations;
}
public boolean hasNorthExit(){
return exitLocations.contains(NORTH_EXIT);
}
public static void main(String[] args) {
LocationWithExits testLocation=new LocationWithExits(NORTH_EXIT+SOUTH_EXIT);
System.out.println("Has exit on north?: "+testLocation.hasNorthExit());
}
}
using array of booleans might cause a lot of problems if you forget what exactly means bexits[0]. Os it for north or south? etc.
如果您忘记了 bexits[0] 的确切含义,则使用布尔数组可能会导致很多问题。O它是北方还是南方?等等。
or you can just use enums and list of exits available . Then in methid test if list contain a certain enum value
或者你可以只使用枚举和可用的退出列表。然后在methid测试中,如果列表包含某个枚举值
回答by Robby Cornelissen
Given what your code looks like, this is the most readable implementation I could come up with:
鉴于您的代码是什么样的,这是我能想到的最易读的实现:
public class Exits {
private static final char[] DIRECTIONS = "NSEWUD".toCharArray();
public static void main(String... args) {
String input = "N S E";
boolean[] exits = new boolean[DIRECTIONS.length];
for(int i = 0; i< exits.length; i++) {
if (input.indexOf(DIRECTIONS[i]) >= 0) {
exits[i] = true;
}
}
}
}
That being said, there's a number of cleaner solutions possible. Personally I would go with enums and an EnumSet
.
话虽如此,可能有许多更清洁的解决方案。就个人而言,我会使用枚举和EnumSet
.
By the way, your original code is incorrect, as it will set as most one value in the array to true.
顺便说一句,您的原始代码不正确,因为它将数组中的最多一个值设置为 true。
回答by EpicPandaForce
Personally, I think you can hack it around a bit using an enum and turn the following:
就个人而言,我认为您可以使用枚举对其进行一些修改并进行以下操作:
public void setExits(String e) {
if (e.contains("N"))
bexits[0] = true;
else if (e.contains("W"))
bexits[1] = true;
else if (e.contains("S"))
bexits[2] = true;
else if (e.contains("E"))
bexits[3] = true;
else if (e.contains("U"))
bexits[4] = true;
else if (e.contains("D"))
bexits[5] = true;
}
into
进入
public enum Directions
{
NORTH("N"),
WEST("W"),
SOUTH("S"),
EAST("E"),
UP("U"),
DOWN("D");
private String identifier;
private Directions(String identifier)
{
this.identifier = identifier;
}
public String getIdentifier()
{
return identifier;
}
}
and then do:
然后做:
public void setExits(String e)
{
String[] exits = e.split(" ");
for(String exit : exits)
{
for(Directions direction : Directions.values())
{
if(direction.getIdentifier().equals(exit))
{
bexits[direction.ordinal()] = true;
break;
}
}
}
}
Although after having written it down, I can't really tell you if it's that much better. It's easier to add new directions, that's for sure.
虽然写下来之后,我真的不能告诉你它是否更好。添加新路线更容易,这是肯定的。
回答by gexicide
The most efficient andexpressive way is the following:
最有效和最具表现力的方式如下:
Use enum
s as Exits and use an EnumSet
to store them. EnumSet
is an efficient Set
implementation that uses a bit field to represent the enum constants.
使用enum
s 作为 Exits 并使用 anEnumSet
来存储它们。EnumSet
是一种Set
使用位域来表示枚举常量的高效实现。
Here is how you can do it:
您可以这样做:
public enum Exit { North, West, South, East, Up, Down; }
EnumSet<Exit> set = EnumSet.noneOf(Exit.class); // An empty set.
// Now you can simply add or remove exits, everything will be stored compactly
set.add(Exit.North); // Add exit
set.contains(Exit.West); // Test if an exit is present
set.remove(Exit.South); //Remove an exit
Enum set will store all exits in a single long
internally, so your code is expressive, fast, and saves a lot of memory.
Enum set 会将所有出口存储在一个long
内部,因此您的代码具有表现力,速度快,并节省了大量内存。
回答by kajacx
OK, first of all, your setExits()
method will not work as intended, chained if-elseif will maximally execute 1 branch of code, for example:
好的,首先,您的setExits()
方法不会按预期工作,链接的 if-elseif 将最大程度地执行 1 个代码分支,例如:
if (e.contains("N"))
bexits[0] = true;
else if (e.contains("W"))
bexits[1] = true;
Even if e
contains both N
and W
, only bexits[0]
will be set. Also this method will only add exits (for example calling setExits("")
will not delete any existing exits.
即使e
同时包含N
和W
,也只会bexits[0]
被设置。此外,此方法只会添加出口(例如调用setExits("")
不会删除任何现有出口。
I would change that method to:
我会将该方法更改为:
bexits[0] = e.contains("N");
bexits[1] = e.contains("W");
...
Also, i definetly wouldn't remember that north is on index 0, west in on 1, ... so a common practice is to name your indexes using final static constants:
另外,我绝对不会记得北在索引 0 上,西在 1 上,...所以通常的做法是使用最终静态常量命名索引:
public static final int NORTH = 0;
public static final int WEST = 1;
...
Then you can write in your setExits
method:
然后你可以在你的setExits
方法中写:
bexits[NORTH] = e.contains("N");
bexits[WEST] = e.contains("W");
...
(much more readible)
(更易读)
Finally, if you want your code even more well-arranged, you can make a Exits
class representing avaliable exits, and backed by boolean array. Then on place where you create your String, you could create this class instead and save yourself work with generating and then parsing a string.
最后,如果您希望您的代码更加Exits
有序,您可以创建一个表示可用退出的类,并由布尔数组支持。然后在你创建你的字符串的地方,你可以创建这个类,并节省自己生成然后解析字符串的工作。
EDIT:
编辑:
as @gexicide answers, there is a really handy class EnumSet
which would be probably better for representing the exits than bollean array.
正如@gexicide 的回答,有一个非常方便的类EnumSet
,它可能比 bollean 数组更适合表示退出。
回答by Syam S
All the approaches listed in the answeres are good. But I think the approach you need to take depends on the way you are going to use the exit field. For example if you are going to handle exit as strings then Ross Drews approach would require a lot of if-else conditions and variables.
答案中列出的所有方法都很好。但我认为您需要采取的方法取决于您将使用退出字段的方式。例如,如果您要将退出作为字符串处理,那么 Ross Drews 方法将需要大量 if-else 条件和变量。
String exit = "N E";
String[] exits = exit.split(" ");
boolean N = false, E = false, S = false, W = false, U = false, D = false;
for(String e : exits){
if(e.equalsIgnoreCase("N")){
N = true;
} else if(e.equalsIgnoreCase("E")){
E = true;
} else if(e.equalsIgnoreCase("W")){
W= true;
} else if(e.equalsIgnoreCase("U")){
U = true;
} else if(e.equalsIgnoreCase("D")){
D = true;
} else if(e.equalsIgnoreCase("S")){
S = true;
}
}
setExits(N, E, S, W, U, D);
Also if you have an exit and you want to check whether a location has that particular exit then again you will have to do the same
此外,如果您有一个出口并且您想检查某个位置是否有该特定出口,那么您将不得不再次执行相同的操作
public boolean hasExit(String exit){
if(e.equalsIgnoreCase("N")){
return this.N; // Or the corresponding getter method
} else if(e.equalsIgnoreCase("E")){
return this.E;
} else if(e.equalsIgnoreCase("W")){
return this.W;
} else if(e.equalsIgnoreCase("U")){
return this.U;
} else if(e.equalsIgnoreCase("D")){
return this.D;
} else if(e.equalsIgnoreCase("S")){
return this.S;
}
}
So if you are going to manipulate it as a string, in my opinion the best approach would be to go for list and enum. By this way you could do methods like hasExit, hasAnyExit, hasAllExits, hasNorthExit, hasSouthExit, getAvailableExits etc etc.. very easily. And considering the number of exits (6) using a list (or set) wont be an overhead. For example
因此,如果您要将其作为字符串进行操作,在我看来,最好的方法是使用 list 和 enum。通过这种方式,您可以非常轻松地执行 hasExit、hasAnyExit、hasAllExits、hasNorthExit、hasSouthExit、getAvailableExits 等方法。考虑到使用列表(或集合)的出口数量(6)不会是一个开销。例如
Enum
枚举
public enum EXIT {
EAST("E"),
WEST("W"),
NORTH("N"),
SOUTH("S"),
UP("U"),
DOWN("D");
private String exitCode;
private EXIT(String exitCode) {
this.exitCode = exitCode;
}
public String getExitCode() {
return exitCode;
}
public static EXIT fromValue(String exitCode) {
for (EXIT exit : values()) {
if (exit.exitCode.equalsIgnoreCase(exitCode)) {
return exit;
}
}
return null;
}
public static EXIT fromValue(char exitCode) {
for (EXIT exit : values()) {
if (exit.exitCode.equalsIgnoreCase(String.valueOf(exitCode))) {
return exit;
}
}
return null;
}
}
Location.java
位置.java
import java.util.ArrayList;
import java.util.List;
public class Location {
private List<EXIT> exits;
public Location(){
exits = new ArrayList<EXIT>();
}
public void setExits(String exits) {
for(char exitCode : exits.toCharArray()){
EXIT exit = EXIT.fromValue(exitCode);
if(exit != null){
this.exits.add(exit);
}
}
}
public boolean hasExit(String exitCode){
return exits.contains(EXIT.fromValue(exitCode));
}
public boolean hasAnyExit(String exits){
for(char exitCode : exits.toCharArray()){
if(this.exits.contains(EXIT.fromValue(exitCode))){
return true;
}
}
return false;
}
public boolean hasAllExit(String exits){
for(char exitCode : exits.toCharArray()){
EXIT exit = EXIT.fromValue(exitCode);
if(exit != null && !this.exits.contains(exit)){
return false;
}
}
return true;
}
public boolean hasExit(char exitCode){
return exits.contains(EXIT.fromValue(exitCode));
}
public boolean hasNorthExit(){
return exits.contains(EXIT.NORTH);
}
public boolean hasSouthExit(){
return exits.contains(EXIT.SOUTH);
}
public List<EXIT> getExits() {
return exits;
}
public static void main(String args[]) {
String exits = "N E W";
Location location = new Location();
location.setExits(exits);
System.out.println(location.getExits());
System.out.println(location.hasExit('W'));
System.out.println(location.hasAllExit("N W"));
System.out.println(location.hasAnyExit("U D"));
System.out.println(location.hasNorthExit());
}
}
回答by Tim B
The EnumSet
in the other answer is the best way to do this, I just wanted to add one more thing though for the future when you start looking not just at whether you can move but where you are moving to.
将EnumSet
在对方的回答是做到这一点的最好办法,我只是想补充一点,虽然对于未来,当你刚开始你是否可以移动但如果你正在向不看。
As well as EnumSet
you also have EnumMap
.
以及EnumSet
你也有EnumMap
。
If you define a Room class/interface then inside the Room class you can have
如果你定义了一个 Room 类/接口,那么在 Room 类中你可以拥有
Map<Direction, Room> exits = new EnumMap<>(Direction.class);
You can now add your links into the map as follows:
您现在可以将链接添加到地图中,如下所示:
exits.put(Direction.NORTH, theRoomNorthOfMe);
Then your code to move between rooms can be very general purpose:
那么您在房间之间移动的代码可能非常通用:
Room destination=currentRoom.getExit(directionMoved);
if (destination == null) {
// Cannot move that way
} else {
// Handle move to destination
}