替换用于在 kotlin 中搜索列表的循环
Replacing for loops for searching list in kotlin
我正在尝试使用 Kotlin's built-in
函数尽可能干净地转换我的代码。我已经使用 for loops
完成了部分代码。但我想知道用于此应用程序的高效内置函数
我有两个 array lists
accounts
和 cards
。
我的目标是 search
一张特定的卡片,在其 card-number
的帮助下,在名为卡片的数组列表中。
那我得validate the pin
。如果引脚是 correct
,通过获取 gift card's
customerId
我必须 search
array list
中的 account
命名为 accounts
.然后我要update
balance
的account
.
这些是我用过的class
class Account{
constructor( )
var id : String = generateAccountNumber()
var name: String? = null
set(name) = if (name != null) field = name.toUpperCase() else { field = "Unknown User"; println("invalid details\nAccount is not Created");}
var balance : Double = 0.0
set(balance) = if (balance >= 0) field = balance else { field = 0.0 }
constructor(id: String = generateAccountNumber(), name: String?,balance: Double) {
this.id = id
this.balance = balance
this.name = name
}
}
class GiftCard {
constructor( )
var cardNumber : String = generateCardNumber()
var pin: String? = null
set(pin) = if (pin != null) field = pin else { field = "Unknown User"; println("Please set the pin\nCard is not Created");}
var customerId : String = ""
set(customerId) = if (customerId != "") field = customerId else { field = "" }
var cardBalance : Double = 0.0
set(cardBalance) = if (cardBalance > 0) field = cardBalance else { field = 0.0; println("Card is created with zero balance\nPlease deposit") }
var status = Status.ACTIVE
constructor(cardNumber: String = generateCardNumber(),
pin: String,
customerId: String,
cardBalance: Double = 0.0,
status: Status = Status.ACTIVE){
this.cardNumber = cardNumber
this.pin = pin
this.customerId = customerId
this.cardBalance = cardBalance
this.status = status
}
}
这是代码的一部分,我必须更改:
override fun closeCard(cardNumber: String, pin: String): Pair<Boolean, Boolean> {
for (giftcard in giftcards) {
if (giftcard.cardNumber == cardNumber) {
if (giftcard.pin == pin) {
giftcard.status = Status.CLOSED
for (account in accounts)
account.balance = account.balance + giftcard.cardBalance
giftcard.cardBalance = 0.0
return Pair(true,true)
}
\invalid pin
return Pair(true,false)
}
}
\card is not present
return Pair(false,false)
}
可能有上百万种不同的方法可以做到这一点,但这里至少有一些我认为值得分享的语言特性:
fun closeCard(cardNumber: String, pin: String): Pair<Boolean, Boolean> {
val giftCard = giftcards.find { it.cardNumber == cardNumber }
?: return Pair(false, false)
return if (giftCard.pin == pin) {
giftCard.status = Status.CLOSED
accounts.forEach {
it.balance += giftCard.cardBalance
}
Pair(true, true)
} else
Pair(true, false)
}
首先要注意的是 Elvis 运算符 - ?:
- 如果左侧为 null
,则计算表达式的右侧。在这种情况下,如果find
returns null
,相当于没有找到符合要求的卡号,我们会立即return Pair(false, false)
.这是您代码中的最后一步。
从那里开始就很简单了。如果引脚匹配,则使用 forEach
循环遍历 accounts
列表并关闭卡片。如果引脚不匹配,那么我们将直接转到 else
分支。在 kotlin 中,if
可以用作表达式,因此我们可以简单地将 return
语句放在 if
之前,并让它 return 每个表达式的最后一个表达式的结果分支.
PS:我不会说这比你的方式更有效率。这只是使用 built-in 函数的一种方式 - find
和 forEach
- 如您所问,以及其他语言功能。
PPS:我强烈建议尝试寻找另一种方法来更新列表而不改变对象。我不知道你的用例,但这感觉不太thread-safe。我没有post解决这个问题,因为它超出了这个问题的范围。
两个class都不是很地道。 Kotlin class 的主构造函数是隐式的,不需要定义,但是,您显式定义了一个构造函数,因此您添加了另一个空的构造函数。
// good
class C
// bad
class C {
constructor()
}
更进一步,Kotlin 具有命名参数和默认值,因此请充分利用它们。
class Account(
val id: String = generateAccountNumber(),
val name: String = "Unknown User",
val balance: Double = 0.0
)
Double
由于其缺点,基本上对于任何事情来说都是一个非常糟糕的选择,例如 https://www.floating-point-gui.de/ 选择 Int
、Long
,甚至 BigDecimal
会更好。似乎您也不希望余额低于零,在这种情况下请考虑 UInt
和 ULong
.
最后但同样重要的是 class 的可变性。这是有道理的,但也可能很危险。您可以根据自己的需要和要求来决定。
enum class Status {
CLOSED
}
@ExperimentalUnsignedTypes
class Account(private var _balance: UInt) {
val balance get() = _balance
operator fun plusAssign(other: UInt) {
_balance += other
}
}
@ExperimentalUnsignedTypes
class GiftCard(
val number: String,
val pin: String,
private var _status: Status,
private var _balance: UInt
) {
val status get() = _status
val balance get() = _balance
fun close() {
_status = Status.CLOSED
_balance = 0u
}
}
@ExperimentalUnsignedTypes
class Main(val accounts: List<Account>, val giftCards: List<GiftCard>) {
fun closeCard(cardNumber: String, pin: String) =
giftCards.find { it.number == cardNumber }?.let {
(it.pin == pin).andAlso {
accounts.forEach { a -> a += it.balance }
it.close()
}
}
}
inline fun Boolean.andAlso(action: () -> Unit): Boolean {
if (this) action()
return this
}
我们将 return 类型从 Pair<Boolean, Boolean>
更改为更惯用的 Boolean?
,其中 Null
表示我们没有找到任何东西(字面意思是 Null
)、false
PIN 不匹配,true
礼品卡已关闭。我们不再创建一对,因此避免了额外的对象分配。
Boolean.andAlso()
是一个方便的扩展函数,我通常会随身携带它,它类似于 Kotlin 的 STD 中的 Any.also()
,但仅在 Boolean
是时才执行 action
实际上 true
.
我正在尝试使用 Kotlin's built-in
函数尽可能干净地转换我的代码。我已经使用 for loops
完成了部分代码。但我想知道用于此应用程序的高效内置函数
我有两个 array lists
accounts
和 cards
。
我的目标是 search
一张特定的卡片,在其 card-number
的帮助下,在名为卡片的数组列表中。
那我得validate the pin
。如果引脚是 correct
,通过获取 gift card's
customerId
我必须 search
array list
中的 account
命名为 accounts
.然后我要update
balance
的account
.
这些是我用过的class
class Account{
constructor( )
var id : String = generateAccountNumber()
var name: String? = null
set(name) = if (name != null) field = name.toUpperCase() else { field = "Unknown User"; println("invalid details\nAccount is not Created");}
var balance : Double = 0.0
set(balance) = if (balance >= 0) field = balance else { field = 0.0 }
constructor(id: String = generateAccountNumber(), name: String?,balance: Double) {
this.id = id
this.balance = balance
this.name = name
}
}
class GiftCard {
constructor( )
var cardNumber : String = generateCardNumber()
var pin: String? = null
set(pin) = if (pin != null) field = pin else { field = "Unknown User"; println("Please set the pin\nCard is not Created");}
var customerId : String = ""
set(customerId) = if (customerId != "") field = customerId else { field = "" }
var cardBalance : Double = 0.0
set(cardBalance) = if (cardBalance > 0) field = cardBalance else { field = 0.0; println("Card is created with zero balance\nPlease deposit") }
var status = Status.ACTIVE
constructor(cardNumber: String = generateCardNumber(),
pin: String,
customerId: String,
cardBalance: Double = 0.0,
status: Status = Status.ACTIVE){
this.cardNumber = cardNumber
this.pin = pin
this.customerId = customerId
this.cardBalance = cardBalance
this.status = status
}
}
这是代码的一部分,我必须更改:
override fun closeCard(cardNumber: String, pin: String): Pair<Boolean, Boolean> {
for (giftcard in giftcards) {
if (giftcard.cardNumber == cardNumber) {
if (giftcard.pin == pin) {
giftcard.status = Status.CLOSED
for (account in accounts)
account.balance = account.balance + giftcard.cardBalance
giftcard.cardBalance = 0.0
return Pair(true,true)
}
\invalid pin
return Pair(true,false)
}
}
\card is not present
return Pair(false,false)
}
可能有上百万种不同的方法可以做到这一点,但这里至少有一些我认为值得分享的语言特性:
fun closeCard(cardNumber: String, pin: String): Pair<Boolean, Boolean> {
val giftCard = giftcards.find { it.cardNumber == cardNumber }
?: return Pair(false, false)
return if (giftCard.pin == pin) {
giftCard.status = Status.CLOSED
accounts.forEach {
it.balance += giftCard.cardBalance
}
Pair(true, true)
} else
Pair(true, false)
}
首先要注意的是 Elvis 运算符 - ?:
- 如果左侧为 null
,则计算表达式的右侧。在这种情况下,如果find
returns null
,相当于没有找到符合要求的卡号,我们会立即return Pair(false, false)
.这是您代码中的最后一步。
从那里开始就很简单了。如果引脚匹配,则使用 forEach
循环遍历 accounts
列表并关闭卡片。如果引脚不匹配,那么我们将直接转到 else
分支。在 kotlin 中,if
可以用作表达式,因此我们可以简单地将 return
语句放在 if
之前,并让它 return 每个表达式的最后一个表达式的结果分支.
PS:我不会说这比你的方式更有效率。这只是使用 built-in 函数的一种方式 - find
和 forEach
- 如您所问,以及其他语言功能。
PPS:我强烈建议尝试寻找另一种方法来更新列表而不改变对象。我不知道你的用例,但这感觉不太thread-safe。我没有post解决这个问题,因为它超出了这个问题的范围。
两个class都不是很地道。 Kotlin class 的主构造函数是隐式的,不需要定义,但是,您显式定义了一个构造函数,因此您添加了另一个空的构造函数。
// good
class C
// bad
class C {
constructor()
}
更进一步,Kotlin 具有命名参数和默认值,因此请充分利用它们。
class Account(
val id: String = generateAccountNumber(),
val name: String = "Unknown User",
val balance: Double = 0.0
)
Double
由于其缺点,基本上对于任何事情来说都是一个非常糟糕的选择,例如 https://www.floating-point-gui.de/ 选择 Int
、Long
,甚至 BigDecimal
会更好。似乎您也不希望余额低于零,在这种情况下请考虑 UInt
和 ULong
.
最后但同样重要的是 class 的可变性。这是有道理的,但也可能很危险。您可以根据自己的需要和要求来决定。
enum class Status {
CLOSED
}
@ExperimentalUnsignedTypes
class Account(private var _balance: UInt) {
val balance get() = _balance
operator fun plusAssign(other: UInt) {
_balance += other
}
}
@ExperimentalUnsignedTypes
class GiftCard(
val number: String,
val pin: String,
private var _status: Status,
private var _balance: UInt
) {
val status get() = _status
val balance get() = _balance
fun close() {
_status = Status.CLOSED
_balance = 0u
}
}
@ExperimentalUnsignedTypes
class Main(val accounts: List<Account>, val giftCards: List<GiftCard>) {
fun closeCard(cardNumber: String, pin: String) =
giftCards.find { it.number == cardNumber }?.let {
(it.pin == pin).andAlso {
accounts.forEach { a -> a += it.balance }
it.close()
}
}
}
inline fun Boolean.andAlso(action: () -> Unit): Boolean {
if (this) action()
return this
}
我们将 return 类型从 Pair<Boolean, Boolean>
更改为更惯用的 Boolean?
,其中 Null
表示我们没有找到任何东西(字面意思是 Null
)、false
PIN 不匹配,true
礼品卡已关闭。我们不再创建一对,因此避免了额外的对象分配。
Boolean.andAlso()
是一个方便的扩展函数,我通常会随身携带它,它类似于 Kotlin 的 STD 中的 Any.also()
,但仅在 Boolean
是时才执行 action
实际上 true
.