如何使用 sqlite 获取头的最后 运行 的长度
How to get the length of the last run of heads using sqlite
我正在编写一个游戏,其中的游戏玩法取决于从序列中反复找到最后一个 运行 的连续值。玩家被随机选择抛硬币,从而导致一系列的硬币抛掷。例如,如果随机选择爱丽丝和鲍勃抛硬币,他们可能会产生以下正面 (H) 和反面 (T) 序列。
player toss
-------------
Bob H
Bob T
Alice T
Bob T
Bob H
Bob H
Alice T
Alice T
Bob H
Alice H
一个run在这里被定义为一系列连续的头值或尾值。 Alice 的最后 运行 头的长度是 1。对于 Bob,最后的 运行 头的长度是 3.
主要问题:
一个。是否有 SQLite 查询来查找特定玩家最后 运行 个正面的长度?
这个问题类似于SQL query for run-length, or consecutive identical value encoding,但在这种情况下只需要最后运行个头像的长度。
我目前获取特定玩家的结果,使用时间戳按降序排列结果,然后计算连续正面的数量以获得该玩家最后 运行 个正面的长度.这是来自我的 Room DAO 的解决方案的 SQLite 部分,它为玩家获取结果:
@Query("SELECT toss FROM outcome WHERE player = :player ORDER BY auto_timestamp DESC")
List<Boolean> getOutcomes(String player);
使用 Java 循环计算连续头部的数量似乎效率低下,让整数最后 运行 长度由 SQLite 查询生成会更清晰。
两个次要问题:
获取玩家最后 运行 头的长度用于解决另外两个问题,目前在 Java 中实现:
乙。找出球员子集合的头的最小最后 运行 长度。使用 Alice 和 Bob 的数据,如果玩家的子集合是 {Alice, Bob},那么最小的 last 运行 长度是 1,Alice 的 运行 长度。
摄氏度。从给定的玩家子集合中找到具有
last heads 运行 长度小于整数m。如果 m 为 2 或 3,则返回 {Alice},因为她的最后 运行 长度为 1。如果 m 为 4,则返回 {Alice, Bob}。
另外,你知道有没有解决B和C的SQLite查询?
A. Is there an SQLite query to find the length of the last run of heads for a particular player?
您可以编写一个查询,尽管如果要满足大范围的 Android API's/versions.
会相当复杂
例如下面的查询将 return 最后一个 运行 并且适用于大多数 Android 版本 :-
WITH
/* CTE for the player - so only need to replce/bind once */
cte_player(p) AS (
SELECT 'Bob' /*<<<<<<<<<< change as necessary */
),
cte_toss(t) AS (
SELECT 'H' /*<<<<<<<<<< change as/if necessary */
),
/* get the base outcome to start from i.e. the latest row for the player */
cte_base_outcome AS (
SELECT auto_timestamp, toss,player
FROM outcome
WHERE player = (SELECT p FROM cte_player)
AND toss = (SELECT t FROM cte_toss)
ORDER BY auto_timestamp DESC
LIMIT 1
),
/* The recursive CTE */
cte1(auto_timestamp,toss,player) AS (
SELECT auto_timestamp,toss, player
FROM cte_base_outcome
UNION ALL SELECT
(
SELECT auto_timestamp
FROM outcome
WHERE outcome.player = (SELECT p FROM cte_player)
AND outcome.auto_timestamp < cte1.auto_timestamp
AND outcome.toss = (SELECT t FROM cte_toss)
ORDER BY auto_timestamp
DESC LIMIT 1
),
(
SELECT toss
FROM outcome
WHERE outcome.player = (SELECT p FROM cte_player)
AND outcome.auto_timestamp < cte1.auto_timestamp
ORDER BY auto_timestamp
DESC LIMIT 1
),
(
SELECT player
FROM outcome
WHERE outcome.player = (SELECT p FROM cte_player)
AND outcome.auto_timestamp < cte1.auto_timestamp
ORDER BY auto_timestamp DESC
LIMIT 1
)
FROM cte1 WHERE toss = (SELECT t FROM cte_toss) LIMIT 10
)
SELECT count() AS result
FROM cte1
WHERE toss = (SELECT t FROM cte_toss);
Additionally, do you know if there are SQLite queries that solve B and C.?
理解了以上内容后,您就可以继续解决 B 和 C 了。
您不妨参考https://sqlite.org/lang_with.html
以下代码用于测试以上内容:-
DROP TABLE IF EXISTS outcome;
CREATE TABLE IF NOT EXISTS outcome (player TEXT, toss TEXT, auto_timestamp);
INSERT INTO outcome VALUES
('Alice','H',10),
('Bob','H',9),
('Alice','T',8),
('Alice','T',7),
('Bob','H',6),
('Bob','H',5),
('Bob','T',4),
('Alice','T',3),
('Bob','T',2),
('Bob','H',1);
WITH
/* CTE for the player - so only need to replce/bind once */
cte_player(p) AS (
SELECT 'Bob' /*<<<<<<<<<< change as necessary */
),
cte_toss(t) AS (
SELECT 'H' /*<<<<<<<<<< change as/if necessary */
),
/* get the base outcome to start from i.e. the latest row for the player */
cte_base_outcome AS (
SELECT auto_timestamp, toss,player
FROM outcome
WHERE player = (SELECT p FROM cte_player)
AND toss = (SELECT t FROM cte_toss)
ORDER BY auto_timestamp DESC
LIMIT 1
),
/* The recursive CTE */
cte1(auto_timestamp,toss,player) AS (
SELECT auto_timestamp,toss, player
FROM cte_base_outcome
UNION ALL SELECT
(
SELECT auto_timestamp
FROM outcome
WHERE outcome.player = (SELECT p FROM cte_player)
AND outcome.auto_timestamp < cte1.auto_timestamp
AND outcome.toss = (SELECT t FROM cte_toss)
ORDER BY auto_timestamp
DESC LIMIT 1
),
(
SELECT toss
FROM outcome
WHERE outcome.player = (SELECT p FROM cte_player)
AND outcome.auto_timestamp < cte1.auto_timestamp
ORDER BY auto_timestamp
DESC LIMIT 1
),
(
SELECT player
FROM outcome
WHERE outcome.player = (SELECT p FROM cte_player)
AND outcome.auto_timestamp < cte1.auto_timestamp
ORDER BY auto_timestamp DESC
LIMIT 1
)
FROM cte1 WHERE toss = (SELECT t FROM cte_toss) LIMIT 10
)
SELECT count() AS result
FROM cte1
WHERE toss = (SELECT t FROM cte_toss);
/* Cleanup the Testing Environment */
DROP TABLE IF EXISTS outcome;
Bob 和 H 结果是:-
Alice 和 H 结果是:-
对于 Bob 和 T,结果是:-
最后是 Alice 和 T :-
要在 Room 中使用,则 SQL 将被放入 @Query 中,您将指定 function/method return 类型的 Int/int 或 Long/long(单列 return 值不需要 POJO/Entity class)。
例如:-
@Query("WITH " +
"/* CTE for the player - so only need to replace/bind once */ " +
" cte_player(p) AS ( SELECT :player)," +
" cte_toss(t) AS (SELECT :toss)," +
"/* get the base outcome to start from i.e. the latest row for the player */" +
" cte_base_outcome AS (" +
" SELECT auto_timestamp, toss,player " +
" FROM outcome " +
" WHERE player = (SELECT p FROM cte_player) " +
" AND toss = (SELECT t FROM cte_toss) " +
" ORDER BY auto_timestamp DESC " +
" LIMIT 1" +
")," +
"/* The recursive CTE */" +
" cte1(auto_timestamp,toss,player) AS (" +
" SELECT auto_timestamp,toss, player FROM cte_base_outcome " +
" UNION ALL SELECT(SELECT auto_timestamp " +
" FROM outcome " +
" WHERE outcome.player = (SELECT p FROM cte_player) " +
" AND outcome.auto_timestamp < cte1.auto_timestamp " +
" AND outcome.toss = (SELECT t FROM cte_toss) " +
" ORDER BY auto_timestamp DESC " +
" LIMIT 1" +
" )," +
" (" +
" SELECT toss " +
" FROM outcome " +
" WHERE outcome.player = (SELECT p FROM cte_player) " +
" AND outcome.auto_timestamp < cte1.auto_timestamp " +
" ORDER BY auto_timestamp DESC " +
" LIMIT 1" +
" )," +
" (" +
" SELECT player " +
" FROM outcome " +
" WHERE outcome.player = (SELECT p FROM cte_player) " +
" AND outcome.auto_timestamp < cte1.auto_timestamp " +
" ORDER BY auto_timestamp DESC " +
" LIMIT 1" +
" ) " +
" FROM cte1 " +
" WHERE toss = (SELECT t FROM cte_toss) " +
" LIMIT 10" +
") " +
"SELECT count() AS result " +
"FROM cte1 " +
"WHERE toss = (SELECT t FROM cte_toss);")
abstract fun getLastRun(player: String, toss: String): Long
- 注意
LIMIT 10
不应该是必需的,但显然是一种故障保护,您可能希望将其增加到合适的值或将其排除。它限制了递归的次数。但是,在 LIMIT 1
已编码的情况下,只需要获取相应的 1 行即可。
我正在编写一个游戏,其中的游戏玩法取决于从序列中反复找到最后一个 运行 的连续值。玩家被随机选择抛硬币,从而导致一系列的硬币抛掷。例如,如果随机选择爱丽丝和鲍勃抛硬币,他们可能会产生以下正面 (H) 和反面 (T) 序列。
player toss
-------------
Bob H
Bob T
Alice T
Bob T
Bob H
Bob H
Alice T
Alice T
Bob H
Alice H
一个run在这里被定义为一系列连续的头值或尾值。 Alice 的最后 运行 头的长度是 1。对于 Bob,最后的 运行 头的长度是 3.
主要问题:
一个。是否有 SQLite 查询来查找特定玩家最后 运行 个正面的长度?
这个问题类似于SQL query for run-length, or consecutive identical value encoding,但在这种情况下只需要最后运行个头像的长度。
我目前获取特定玩家的结果,使用时间戳按降序排列结果,然后计算连续正面的数量以获得该玩家最后 运行 个正面的长度.这是来自我的 Room DAO 的解决方案的 SQLite 部分,它为玩家获取结果:
@Query("SELECT toss FROM outcome WHERE player = :player ORDER BY auto_timestamp DESC")
List<Boolean> getOutcomes(String player);
使用 Java 循环计算连续头部的数量似乎效率低下,让整数最后 运行 长度由 SQLite 查询生成会更清晰。
两个次要问题:
获取玩家最后 运行 头的长度用于解决另外两个问题,目前在 Java 中实现:
乙。找出球员子集合的头的最小最后 运行 长度。使用 Alice 和 Bob 的数据,如果玩家的子集合是 {Alice, Bob},那么最小的 last 运行 长度是 1,Alice 的 运行 长度。
摄氏度。从给定的玩家子集合中找到具有 last heads 运行 长度小于整数m。如果 m 为 2 或 3,则返回 {Alice},因为她的最后 运行 长度为 1。如果 m 为 4,则返回 {Alice, Bob}。
另外,你知道有没有解决B和C的SQLite查询?
A. Is there an SQLite query to find the length of the last run of heads for a particular player?
您可以编写一个查询,尽管如果要满足大范围的 Android API's/versions.
会相当复杂例如下面的查询将 return 最后一个 运行 并且适用于大多数 Android 版本 :-
WITH
/* CTE for the player - so only need to replce/bind once */
cte_player(p) AS (
SELECT 'Bob' /*<<<<<<<<<< change as necessary */
),
cte_toss(t) AS (
SELECT 'H' /*<<<<<<<<<< change as/if necessary */
),
/* get the base outcome to start from i.e. the latest row for the player */
cte_base_outcome AS (
SELECT auto_timestamp, toss,player
FROM outcome
WHERE player = (SELECT p FROM cte_player)
AND toss = (SELECT t FROM cte_toss)
ORDER BY auto_timestamp DESC
LIMIT 1
),
/* The recursive CTE */
cte1(auto_timestamp,toss,player) AS (
SELECT auto_timestamp,toss, player
FROM cte_base_outcome
UNION ALL SELECT
(
SELECT auto_timestamp
FROM outcome
WHERE outcome.player = (SELECT p FROM cte_player)
AND outcome.auto_timestamp < cte1.auto_timestamp
AND outcome.toss = (SELECT t FROM cte_toss)
ORDER BY auto_timestamp
DESC LIMIT 1
),
(
SELECT toss
FROM outcome
WHERE outcome.player = (SELECT p FROM cte_player)
AND outcome.auto_timestamp < cte1.auto_timestamp
ORDER BY auto_timestamp
DESC LIMIT 1
),
(
SELECT player
FROM outcome
WHERE outcome.player = (SELECT p FROM cte_player)
AND outcome.auto_timestamp < cte1.auto_timestamp
ORDER BY auto_timestamp DESC
LIMIT 1
)
FROM cte1 WHERE toss = (SELECT t FROM cte_toss) LIMIT 10
)
SELECT count() AS result
FROM cte1
WHERE toss = (SELECT t FROM cte_toss);
Additionally, do you know if there are SQLite queries that solve B and C.?
理解了以上内容后,您就可以继续解决 B 和 C 了。
您不妨参考https://sqlite.org/lang_with.html
以下代码用于测试以上内容:-
DROP TABLE IF EXISTS outcome;
CREATE TABLE IF NOT EXISTS outcome (player TEXT, toss TEXT, auto_timestamp);
INSERT INTO outcome VALUES
('Alice','H',10),
('Bob','H',9),
('Alice','T',8),
('Alice','T',7),
('Bob','H',6),
('Bob','H',5),
('Bob','T',4),
('Alice','T',3),
('Bob','T',2),
('Bob','H',1);
WITH
/* CTE for the player - so only need to replce/bind once */
cte_player(p) AS (
SELECT 'Bob' /*<<<<<<<<<< change as necessary */
),
cte_toss(t) AS (
SELECT 'H' /*<<<<<<<<<< change as/if necessary */
),
/* get the base outcome to start from i.e. the latest row for the player */
cte_base_outcome AS (
SELECT auto_timestamp, toss,player
FROM outcome
WHERE player = (SELECT p FROM cte_player)
AND toss = (SELECT t FROM cte_toss)
ORDER BY auto_timestamp DESC
LIMIT 1
),
/* The recursive CTE */
cte1(auto_timestamp,toss,player) AS (
SELECT auto_timestamp,toss, player
FROM cte_base_outcome
UNION ALL SELECT
(
SELECT auto_timestamp
FROM outcome
WHERE outcome.player = (SELECT p FROM cte_player)
AND outcome.auto_timestamp < cte1.auto_timestamp
AND outcome.toss = (SELECT t FROM cte_toss)
ORDER BY auto_timestamp
DESC LIMIT 1
),
(
SELECT toss
FROM outcome
WHERE outcome.player = (SELECT p FROM cte_player)
AND outcome.auto_timestamp < cte1.auto_timestamp
ORDER BY auto_timestamp
DESC LIMIT 1
),
(
SELECT player
FROM outcome
WHERE outcome.player = (SELECT p FROM cte_player)
AND outcome.auto_timestamp < cte1.auto_timestamp
ORDER BY auto_timestamp DESC
LIMIT 1
)
FROM cte1 WHERE toss = (SELECT t FROM cte_toss) LIMIT 10
)
SELECT count() AS result
FROM cte1
WHERE toss = (SELECT t FROM cte_toss);
/* Cleanup the Testing Environment */
DROP TABLE IF EXISTS outcome;
Bob 和 H 结果是:-
Alice 和 H 结果是:-
对于 Bob 和 T,结果是:-
最后是 Alice 和 T :-
要在 Room 中使用,则 SQL 将被放入 @Query 中,您将指定 function/method return 类型的 Int/int 或 Long/long(单列 return 值不需要 POJO/Entity class)。
例如:-
@Query("WITH " +
"/* CTE for the player - so only need to replace/bind once */ " +
" cte_player(p) AS ( SELECT :player)," +
" cte_toss(t) AS (SELECT :toss)," +
"/* get the base outcome to start from i.e. the latest row for the player */" +
" cte_base_outcome AS (" +
" SELECT auto_timestamp, toss,player " +
" FROM outcome " +
" WHERE player = (SELECT p FROM cte_player) " +
" AND toss = (SELECT t FROM cte_toss) " +
" ORDER BY auto_timestamp DESC " +
" LIMIT 1" +
")," +
"/* The recursive CTE */" +
" cte1(auto_timestamp,toss,player) AS (" +
" SELECT auto_timestamp,toss, player FROM cte_base_outcome " +
" UNION ALL SELECT(SELECT auto_timestamp " +
" FROM outcome " +
" WHERE outcome.player = (SELECT p FROM cte_player) " +
" AND outcome.auto_timestamp < cte1.auto_timestamp " +
" AND outcome.toss = (SELECT t FROM cte_toss) " +
" ORDER BY auto_timestamp DESC " +
" LIMIT 1" +
" )," +
" (" +
" SELECT toss " +
" FROM outcome " +
" WHERE outcome.player = (SELECT p FROM cte_player) " +
" AND outcome.auto_timestamp < cte1.auto_timestamp " +
" ORDER BY auto_timestamp DESC " +
" LIMIT 1" +
" )," +
" (" +
" SELECT player " +
" FROM outcome " +
" WHERE outcome.player = (SELECT p FROM cte_player) " +
" AND outcome.auto_timestamp < cte1.auto_timestamp " +
" ORDER BY auto_timestamp DESC " +
" LIMIT 1" +
" ) " +
" FROM cte1 " +
" WHERE toss = (SELECT t FROM cte_toss) " +
" LIMIT 10" +
") " +
"SELECT count() AS result " +
"FROM cte1 " +
"WHERE toss = (SELECT t FROM cte_toss);")
abstract fun getLastRun(player: String, toss: String): Long
- 注意
LIMIT 10
不应该是必需的,但显然是一种故障保护,您可能希望将其增加到合适的值或将其排除。它限制了递归的次数。但是,在LIMIT 1
已编码的情况下,只需要获取相应的 1 行即可。