我试图编写一个案例陈述,其中包含两个条件,如下所示:
class Pokemon:
def __init__(self, kind, level):
self.level = level
self.kind = kind # The kind is just a component now.
def evolve(self):
# Create a new instance of the next evolution stage
# and use it to replace the previous kind.
self.kind = self.kind.evolution_stage()
class Bulbasaur:
def __init__(self):
self.base_health = 45
# A reference to the next evolution stage class.
self.evolution_stage = Ivysaur
class Ivysaur:
def __init__(self):
self.base_health = 60
# self.evolution_stage = Venusaur
# Pass a Bulbasaur instance as the `kind` argument.
pokemons = [Pokemon(Bulbasaur(), 3)]
print(pokemons[0].kind, pokemons[0].kind.base_health)
pokemons[0].evolve() # Changes the .kind attribute.
print(pokemons[0].kind, pokemons[0].kind.base_health)
我很乐意让这个工作。我更愿意理解为什么我的例子失败了。
已编辑添加:
感谢所有反馈!灵感,我意识到结合两个案例变量允许我将它们折叠成一个简单的switch语句的单个值......
roll1 = rand(1..6)
roll2 = rand(1..2)
result = case[roll1, roll2]
when [1..3 && 1]
"Low / Low"
when [4..6 && 1]
"High / Low"
when [1..3 && 2]
"Low / High"
when [4..6 && 2]
"JACKPOT!!"
end
puts result
虽然这解决了我眼前的问题,但它并没有提升我的基础知识 - 与我收到的所有令人敬畏的反馈相比,这是一个微不足道的洞察力。真诚的谢谢!
答案 0 :(得分:4)
您的代码有两个问题。首先,这个:
[1..3 && 1]
是一个包含一个元素的数组。由于..
的优先级低于&&
,因此您实际上正在撰写1..(3 && 1)
,这只是一种复杂的1..1
方式。这意味着您的case
确实是:
case[roll1, roll2]
when [1..1]
"Low / Low"
when [4..1]
"High / Low"
when [1..2]
"Low / High"
when [4..2]
"JACKPOT!!"
end
第二个问题是Array
没有覆盖===
使用的case
运算符,因此您将使用Object#===
,它只是{{1}的别名1}}。这意味着您的Object#==
相当于:
case
if([roll1, roll2] == [1..1])
"Low / Low"
elsif([roll1, roll2] == [4..1])
"High / Low"
elsif([roll1, roll2] == [1..2])
"Low / High"
elsif([roll1, roll2] == [4..2])
"JACKPOT!!"
end
永远不会等于[roll1, roll2]
因为[some_range]
逐个元素进行比较而Array#==
永远不会roll1
一个范围;此外,您还要比较不同大小的数组。
这意味着你有一个复杂的说法:
==
我可能只是使用result = nil
:
if
或者您可以明确使用result = if (1..3).include?(roll1) && roll2 == 1
'Low / Low'
elsif (4..6).include?(roll1) && roll2 == 1
'High / Low'
...
:
===
但请注意result = if (1..3) === roll1 && roll2 == 1
'Low / Low'
elsif (4..6) === roll1 && roll2 == 1
'High / Low'
...
的优先级低。
答案 1 :(得分:2)
when语句并不像你想象的那样真正起作用,也不是数组文字。在其基本形式中,import geotrellis.raster._
import geotrellis.spark._
import geotrellis.spark.tiling._
import geotrellis.vector._
import org.apache.spark.HashPartitioner
import org.apache.spark.rdd.RDD
import java.util.UUID
// see https://stackoverflow.com/questions/47359243/geotrellis-get-the-points-that-fall-in-a-polygon-grid-rdd
val pointValueRdd : RDD[Feature[Point,Double]] = ???
val squareGridRdd : RDD[Polygon] = ???
// Since we'll be grouping by key and then joining, it's work defining a partitioner
// up front.
val partitioner = new HashPartitioner(100)
// First, we'll determine the bounds of the Polygon grid
// and the average height and width, to create a GridExtent
val (extent, totalHeight, totalWidth, totalCount) =
squareGridRdd
.map { poly =>
val e = poly.envelope
(e, e.height, e.width, 1)
}
.reduce { case ((extent1, height1, width1, count1), (extent2, height2, width2, count2)) =>
(extent1.combine(extent2), height1 + height2, width1 + width2, count1 + count2)
}
val gridExtent = GridExtent(extent, totalHeight / totalCount, totalWidth / totalCount)
// We then use this for to construct a LayoutDefinition, that represents "tiles"
// that are 1x1.
val layoutDefinition = LayoutDefinition(gridExtent, tileCols = 1, tileRows = 1)
// Now that we have a layout, we can cut the polygons up per SpatialKey, as well as
// assign points to a SpatialKey, using ClipToGrid
// In order to keep track of which polygons go where, we'll assign a UUID to each
// polygon, so that they can be reconstructed. If we were dealing with PolygonFeatures,
// we could store the feature data as well. If those features already had IDs, we could
// also just use those IDs instead of UUIDs.
// We'll also store the original polygon, as they are not too big and it makes
// the reconstruction process (which might be prone to floating point errors) a little
// easier. For more complex polygons this might not be the most performant strategy.
// We then group by key to produce a set of polygons that intersect each key.
val cutPolygons: RDD[(SpatialKey, Iterable[Feature[Geometry, (Polygon, UUID)]])] =
squareGridRdd
.map { poly => Feature(poly, (poly, UUID.randomUUID)) }
.clipToGrid(layoutDefinition)
.groupByKey(partitioner)
// While we could also use clipToGrid for the points, we can
// simply use the mapTransform on the layout to determien what SpatialKey each
// point should be assigned to.
// We also group this by key to produce the set of points that intersect the key.
val pointsToKeys: RDD[(SpatialKey, Iterable[PointFeature[Double]])] =
pointValueRdd
.map { pointFeature =>
(layoutDefinition.mapTransform.pointToKey(pointFeature.geom), pointFeature)
}
.groupByKey(partitioner)
// Now we can join those two RDDs and perform our point in polygon tests.
// Use a left outer join so that polygons with no points can be recorded.
// Once we have the point information, we key the RDD by the UUID and
// reduce the results.
val result: RDD[Feature[Polygon, Double]] =
cutPolygons
.leftOuterJoin(pointsToKeys)
.flatMap { case (_, (polyFeatures, pointsOption)) =>
pointsOption match {
case Some(points) =>
for(
Feature(geom, (poly, uuid)) <- polyFeatures;
Feature(point, value) <- points if geom.intersects(point)
) yield {
(uuid, Feature(poly, (value, 1)))
}
case None =>
for(Feature(geom, (poly, uuid)) <- polyFeatures) yield {
(uuid, Feature(poly, (0.0, 0)))
}
}
}
.reduceByKey { case (Feature(poly1, (accum1, count1)), Feature(poly2, (accum2, count2))) =>
Feature(poly1, (accum1 + accum2, count1 + count2))
}
.map { case (_, feature) =>
// We no longer need the UUID; also compute the mean
feature.mapData { case (acc, c) => acc / c }
}
使用threequals运算符(case
)将顶级表达式与when语句中的表达式进行比较。
在Ruby中,几乎所有东西都是表达式。在您的示例中,您尝试将值数组与解析为单元素数组的数组进行匹配。考虑:
===
基本上,您的顶级数组永远不会匹配您提供的任何数组表达式作为条件。你想要的可能是这样的:
[1..3 && 2]
#=> [1..2]
[1..3 && 2].count
#=> 1
[1..3 && 2].map &:class
#=> [Range]
在这种类型的构造中,您没有使用具有顶级值的三元组表达式来进行比较。相反,你是从一对表达式构造一个truthy或falsey布尔值。使用额外的when语句将其充实,然后在仍然无法进行无效比较时调试表达式。
答案 2 :(得分:0)
除了“JACKPOT!!”
之外,你有两个不同的问题,通过单独处理它们更容易处理。
def result_of_rolls(roll1, roll2)
if (4..6).cover?(roll1) && roll2 == 2
"JACKPOT!!"
else
"%s / %s" % [(1..3).cover?(roll1) ? "Low" : "High",
roll2 == 1 ? "Low" : "High"]
end
end
result_of_rolls(2,1) #=> "Low / Low"
result_of_rolls(4,1) #=> "High / Low"
result_of_rolls(3,2) #=> "Low / High"
result_of_rolls(5,2) #=> "JACKPOT!!"
如果有三个或更多个卷,而不是两个卷,可以看出这种方法比检查roll1
,roll2
的所有值组合的方法更有效, roll3
,等等。
答案 3 :(得分:0)
如果您的示例不仅仅是针对一般情况的人为MCVE,而是您的实际问题,或者如果您的实际问题非常相似,那么还有一些其他想法:
视为两个独立的问题,结合,处理特例:
result = "#{roll1 < 4 ? 'Low' : 'High'} / #{roll2 < 2 ? 'Low' : 'High'}".
sub('High / High', 'JACKPOT!!')
同样的想法写得不同:
result = [roll1 < 4, roll2 < 2].
map { |low| low ? 'Low' : 'High' }.
join(' / ').
sub('High / High', 'JACKPOT!!')
又一次,但有点傻:
result = [roll1 < 4, roll2 < 2].
join(' / ').
gsub('true', 'Low').gsub('false', 'True').
sub('High / High', 'JACKPOT!!')
使用布尔值,因为他们只需要进行==
比较:
result = case [roll1 > 3, roll2 > 1]
when [false, false]
"Low / Low"
when [true, false]
"High / Low"
when [false, true]
"Low / High"
when [true, true]
"JACKPOT!!"
end
(case [(4..6) === roll1, roll2 == 2]
也会有效。请注意我indented differently。)
将卷组合成一个数字:
result = case roll1 * (-1)**roll2
when -3..-1
"Low / Low"
when -6..-4
"High / Low"
when 1..3
"Low / High"
when 4..6
"JACKPOT!!"
end
同样的想法写得不同:
result = case roll2 * 10 + roll1
when 11..13
"Low / Low"
when 14..16
"High / Low"
when 21..23
"Low / High"
when 24..26
"JACKPOT!!"
end
同样,只是不同的代码风格:
result = case roll1 * (-1)**roll2
when -3..-1 then "Low / Low"
when -6..-4 then "High / Low"
when 1..3 then "Low / High"
when 4..6 then "JACKPOT!!"
end