我希望能够在C
中随机选择5行感谢。
答案 0 :(得分:0)
让我们大声思考。
如果您只需要选择5个任意数字,而这些数字恰好总和低于给定 N 的数字,您可以作弊并选择5个最小的数字;如果它们总和大于 N 的数字,选择任何其他数字也不会有帮助,并且您注册了错误。
如果你希望你的数字总结得非常接近 N (用户问20分钟,你尝试提供19分钟而不是5分钟),它就成了一个背包问题,这是很难,但也许各种近似的解决方法可能有所帮助。
如果您只想选择总计 N 的5个随机数,您可以随机选择5个数字(歌曲)并进行检查。您必须限制完成的尝试次数和/或花费的时间,并准备好报告失败。
以某种方式更有效的算法将保留到目前为止所选择的歌曲列表,以及它们的长度之和 s 。它会尝试添加长度≤ N - s 的随机歌曲。如果在几次尝试后失败,它将从列表中删除最长的歌曲并重复。它必须准备好承认失败,这取决于所做的尝试总次数和/或花费的时间。
我不认为简单的SQL查询可以有效地解决这个问题。但是,您可以将上面的算法编码为非常复杂的SQL查询。我宁愿用Python编码它,因为本地SQLite查找非常快,前提是你的歌曲按长度索引。
答案 1 :(得分:0)
一种可能的解决方案是仅选择个别长度<1的歌曲。 500.然后你尽可能多地保留它们。如果您的小于5或总时间<1。 500,然后你迭代或递归,找到未使用时间的一些歌曲。
def createtimeplay(timee, tot = None, tot_time = 0):
if tot is None: tot= [] # at first call initialize the result list
# exclude previously selected songs from the search
qry = "SELECT * FROM songs WHERE length <= ?"
if len(tot) > 0:
qry += " and name not in (" + ','.join(['?'] * len(tot)) + ')'
qry += " ORDER BY RANDOM() LIMIT 5 "
curs = c.execute(qry, [timee] + [song[0] for song in tot])
cur = (curs.fetchall())
if len(cur) == 0: return tot # no song were found: we can return
# keep songs that fit in allowed time
cur_time = 0
for song in cur:
if cur_time + song[1] <= timee:
cur_time += song[1]
tot.append(song)
if (len(tot) == 5) return tot # never more than 5 songs
tot_time += cur_time # total songs time
if len(tot) != 5 and cur_time != timee: # if not all recurse
createtimeplay(timee - tot_time, tot, tot_time)
return tot
诀窍是我们传递一个可修改对象的列表,因此所有递归调用都会将歌曲添加到同一列表中。
然后您可以使用:
>>> print(createtimeplay(500))
[('Song 18', 350, 'Country', 'z'), ('Song 4', 150, 'Pop', 'x')]
>>> print(createtimeplay(500))
[('Song 12', 200, 'Country', 'z'), ('Song 3', 100, 'Country', 'z'), ('Song 14', 200, 'Rap', 'y')]
>>> print(createtimeplay(500))
[('Song 5', 300, 'Rap', 'y'), ('Song 7', 200, 'Pop', 'x')]
>>>
但是之前的解决方案效率非常低:当每个查询都是全表扫描时,它需要多个查询,因为顺序是random(),并且当它可以轻松避免时使用递归。只在sqlite级别进行全表扫描,在sqlite或Python中对结果进行混洗,然后只扫描一次完整的随机歌曲列表,保持最大数量为5,并且约束为sqlite,这样既简单又高效。总长度。
代码现在变得更加简单:
def createtimeplay(tim, n, con):
songs = c.execute("""SELECT name, length, genre, artist
FROM songs
WHERE length < ? ORDER BY RANDOM()""", (tim,)).fetchall()
result = []
tot = 0
for song in songs:
if song[1] <= tim:
tim -= song[1]
result.append(song)
if len(result) == n or tim == 0: break
return result
在这段代码中,我选择将最大数量和光标或连接传递给sqlite数据库作为参数。