![](/img/trans.png)
[英]the quickest way to Implement an algorithm to count how many times each string is present in an array of strings using Java
[英]Elegant way to count how many pieces of each type are present in a position
我有一个抽象的 class 有 1 个属性,如下所示:
PieceColor {
WHITE, BLACK
}
abstract class Piece {
PieceColor color
abstract char getAbbr();
}
此 class 棋子已由 Bishop Knight Rook King Queen 和 Pawn 类扩展。 每个 class 都有一个名为 getAbbr() 的方法,它返回 Piece 的缩写 KQBNRP。
现在我有一个Map<Piece, Tile> piecePlacements
,它代表特定时间当前棋盘上的所有棋子。
我需要计算有多少种类型的棋子,比如白车、黑皇后等。但是这样做的正常方法太长了,而且很难看。 我就是这样做的...
//0: White pieces, 1: Black pieces; 0-5: KQRBNP
int[][] pieceCount = new int[2][6];
for(Piece piece : piecePlacements.keySet()) {
switch (piece.getAbbr()) {
case 'K' :
if (piece.color == PieceColor.WHITE) {
pieceCount[0][0]++;
} else {
pieceCount[1][0]++;
}
break;
case 'Q' :
if (piece.color == PieceColor.WHITE) {
pieceCount[0][1]++;
} else {
pieceCount[1][1]++;
}
break;
case 'R' :
if (piece.color == PieceColor.WHITE) {
pieceCount[0][2]++;
} else {
pieceCount[1][2]++;
}
break;
case 'B' :
if (piece.color == PieceColor.WHITE) {
pieceCount[0][3]++;
} else {
pieceCount[1][3]++;
}
break;
case 'N' :
if (piece.color == PieceColor.WHITE) {
pieceCount[0][4]++;
} else {
pieceCount[1][4]++;
}
break;
case 'P' :
if (piece.color == PieceColor.WHITE) {
pieceCount[0][5]++;
} else {
pieceCount[1][5]++;
}
break;
}
}
必须有一种更优雅的方法,它需要更少的代码行。 我的意思是如果有超过 6 种类型的部件和 2 种类型的 colors。 我不能像这样继续在 switch 语句中添加案例吗? 但我不知道如何使它更优雅。
执行此操作的正常方法是使用 枚举器(在 Java 中称为enum
)。 枚举器让您定义一组值,它们会自动完成所有 rest 的工作,例如为每个值分配一个唯一的 ID,在后台。 这是一个简单的例子:
public enum PieceType {
KING,
QUEEN,
ROOK,
BISHOP,
KNIGHT,
PAWN;
}
然后你可以在你的Piece
class 中使用它。 我还将添加适当的封装,这是您应该遵循的。
public class Piece {
private final PieceType type;
private final boolean isBlack;
public Piece(PieceType type, boolean isBlack) {
this.type = type;
this.isBlack = isBlack;
}
public PieceType getType() {
return type;
}
public boolean isBlack() {
return isBlack;
}
}
现在我们已经完成了所有设置,编写 for 循环变得微不足道:
for (Piece piece : piecePlacements) {
pieceCount[piece.isBlack() ? 1 : 0][piece.getType().ordinal()]++;
}
对于第一个维度的索引,我们使用三元运算符。 这允许我们编写条件表达式而无需写出整个 if 语句。 在这种情况下,如果piece.isBlack()
为真,则插入索引1
,否则插入索引0
。
对于第二个维度的索引,我们使用ordinal()
方法。 这是所有枚举器都隐含的特殊方法。 它返回给定枚举器值的唯一 ID,而且好的部分是,您不必担心它是如何得出该 ID 的。 它会自动完成这一切。
为每件作品的颜色和角色定义枚举。
使用错误命名的Enum#ordinal
获取每个枚举对象在其定义中的 position 的索引号。 使用该数字作为 arrays 的索引。
for ( Piece piece : pieces ) // `Piece` is class with two member fields: a `Color` enum object and a `Role` enum object.
{
pieceCount // Your two-dimensional array.
[ piece.color().ordinal() ] // Get the `Piece` object’s `Color` enum object’s definition position.
[ piece.role().ordinal() ] // Get the `Piece` object’s `Role` enum object’s definition position.
++ // Using those two index numbers as index into your arrays, increment the count.
;
}
使用枚举使这项任务变得更加简单。
枚举提供了方法ordinal
,这是用词不当,因为它实际上返回了定义枚举 object 的顺序的从零开始的索引(不是从一开始的序数)。 我们可以使用这个枚举索引号作为 arrays 的索引。
让我们使用一对嵌套枚举Color
和Role
来定义您的Piece
记录。
记录是 Java 16 中的一个新功能,用于编写 class 的简要方法,其主要目的是透明和不可变地传递数据。 编译器隐式创建构造函数、getter、 equals
& hashCode
和toString
。 此解决方案不是必需的,但非常适合您的Piece
class。
package work.basil.example.chess;
public record Piece(Color color , Role role)
{
public enum Color
{ WHITE, BLACK }
public enum Role
{ KING, QUEEN, ROOK, BISHOP, KNIGHT, PAWN }
}
所以Piece.Color.WHITE.ordinal()
返回 0,而BLACK
返回 1。
我们需要一些样本数据。
List < Piece > pieces = List.of(
new Piece( Piece.Color.BLACK , Piece.Role.QUEEN ) ,
new Piece( Piece.Color.BLACK , Piece.Role.KNIGHT ) ,
new Piece( Piece.Color.WHITE , Piece.Role.PAWN )
);
我们可以通过询问每个枚举的长度,以软编码方式定义您的 arrays。
int[][] pieceCount = new int[ Piece.Color.values().length ][ Piece.Role.values().length ]; // [2][6]
接下来,我们在板上循环棋子。 我们通过调用错误命名的ordinal()
方法询问每个Piece
对象的Color
和Role
枚举成员字段 object 的索引 position。
for ( Piece piece : pieces )
{
pieceCount[ piece.color().ordinal() ][ piece.role().ordinal() ]++;
}
这是整个示例应用程序 class。
package work.basil.example.chess;
import java.util.Arrays;
import java.util.List;
public class App
{
public static void main ( String[] args )
{
App app = new App();
app.demo();
}
private void demo ( )
{
List < Piece > pieces = List.of(
new Piece( Piece.Color.BLACK , Piece.Role.QUEEN ) ,
new Piece( Piece.Color.BLACK , Piece.Role.KNIGHT ) ,
new Piece( Piece.Color.WHITE , Piece.Role.PAWN )
);
int[][] pieceCount = new int[ Piece.Color.values().length ][ Piece.Role.values().length ]; // [2][6]
for ( Piece piece : pieces )
{
pieceCount[ piece.color().ordinal() ][ piece.role().ordinal() ]++;
}
System.out.println( "pieces = " + pieces );
for ( int i = 0 ; i < pieceCount.length ; i++ )
{
System.out.println( Arrays.toString( pieceCount[ i ] ) );
}
}
}
跑的时候。
pieces = [Piece[color=BLACK, role=QUEEN], Piece[color=BLACK, role=KNIGHT], Piece[color=WHITE, role=PAWN]]
[0, 0, 0, 0, 0, 1]
[0, 1, 0, 0, 1, 0]
除了巧妙地解决您的挑战之外,使用 Java 枚举还提供了另外三个重大胜利:
首先对事物进行排序通常可以加快计数速度。 如果您知道顺序,则可以减少测试次数。
另一个角度是每个项目都有一个质数。 将每个相乘成一个总数。 然后除以该素数以获得相应项目的计数。
但实际上,正确的答案可能涉及枚举。 此外,更少的代码行并不一定意味着计算更快或更有效。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.