对具有不确定数据的数组进行排序
Posted
技术标签:
【中文标题】对具有不确定数据的数组进行排序【英文标题】:Sorting arrays with uncertain data 【发布时间】:2016-04-04 19:17:22 【问题描述】:我正在为浏览器游戏制作一个脚本,该脚本将生成一个随机动物供玩家使用 0-5 标记进行战斗。该动物身上的标记是随机生成的,并被输入一个自定义的 imagick 函数,该函数将按照它们在数组中出现的顺序添加它们。
虽然标记是随机决定的,但它们应该如何出现在动物身上有很多规则,例如“全身”区域的标记显示在“腹部”区域的标记之上。为了更好地解释,我将附上迄今为止测试人员的图像:
所以要分解这个随机生成的动物身上的 5 个标记,eyeshadow
标记属于眼睛区域,undertail
属于尾巴,streaks
属于全身,appaloosa
属于背部,@987654328 @属于腿。现在的订单只是在脚本循环访问数据库并随机选择标记时添加的,所以 okapi(腿上的条纹)位于最上面,因为它是数组中的最后一个,并且是添加的最后一个。但是按照顺序规则,数组中的最后一个应该是条纹(身体上的水平条纹),因为全身标记在顶部。
这是选择标记的代码,这是使用 Laravel 引擎完成的:
// Determine number of markings
$num = mt_rand(1,10);
if ($num == 1)
$markingNum = 0;
elseif ($num > 1 && $num < 4)
$markingNum = 1;
elseif ($num > 4 && $num < 6)
$markingNum = 2;
elseif ($num > 6 && $num < 8)
$markingNum = 3;
elseif ($num > 8 && $num < 10)
$markingNum = 4;
else
$markingNum = 5;
// Calculate Marking type and color
$markings = array();
if ($markingNum > 0)
for ($m = 0 ; $m < $markingNum; $m++)
// Set color values (pulls from the "pallet" selected earlier in the code, which will determine the range of color that marking can be)
if ($m == 1)
$pal = $pallet->marking1;
elseif ($m == 2)
$pal = $pallet->marking2;
elseif ($m == 3)
$pal = $pallet->marking3;
elseif ($m == 4)
$pal = $pallet->marking4;
else
$pal = $pallet->marking5;
// Pull previous marking info
if (count($markings) != 0)
$previous = DataMarking::whereIn('name', array_keys($markings))->get();
// This pulls the regions of the current markings in the array so it won't select a region that already has a marking.
foreach ($previous as $p)
$regions[$p->region] = $p->name;
// Uncommon marking (10% chance)
$r = mt_rand(1, 10);
if ($r == 10)
$marking = DataMarking::where('rarity', 1)
->where('public', 1)
->whereNotIn('name', array_keys($markings))
->whereNotIn('region', array_keys($regions))
->orderByRaw("RAND()")
->first();
// Common markings
else
$marking = DataMarking::where('rarity', 0)
->where('public', 1)
->whereNotIn('name', array_keys($markings))
->whereNotIn('region', array_keys($regions))
->orderByRaw("RAND()")
->first();
// Colors marking
if ($pal == 0)
$markingColor = rand_color();
else
$range = ColorRange::where('id', $pal)->firstOrFail();
$markingColor = "#" . mixRange(substr($range->start_hex, 1), substr($range->end_hex, 1));
$markings[$marking->name] = $markingColor;
else
// Uncommon marking (10% chance)
$r = mt_rand(1, 10);
if ($r == 10)
$marking = DataMarking::where('rarity', 1)
->where('public', 1)
->orderByRaw("RAND()")->first();
// Common marking
else
$marking = DataMarking::where('rarity', 0)
->where('public', 1)
->orderByRaw("RAND()")->first();
// Colors marking
if ($pal == 0)
$markingColor = rand_color();
else
$range = ColorRange::where('id', $pal)->firstOrFail();
$markingColor = "#" . mixRange(substr($range->start_hex, 1), substr($range->end_hex, 1));
$markings[$marking->name] = $markingColor;
我认为我可以使用许多复杂的 if 语句来完成此任务,但它对我来说似乎不是一个优雅的解决方案。此外,还有一个例外:“渐变”,一个全身标记,即使它是一个全身标记,它也会出现在所有物体的下方。不过,到目前为止,它是唯一一个具有这种例外的标记。
我尝试过使用 php 提供的各种 sort
函数,但运气不佳。 uksort
似乎是最有希望的,但由于我们排序的值存在于数据库中而不是我们排序的数组中(imagick 函数必须输入标记 => 颜色数组格式),事实证明很难工作与。
Tl;dr:我需要根据数据库中存在的键值(标记区域)重新排序一个不确定数据量的数组。实现此目的最优雅的方法是什么?
【问题讨论】:
我喜欢有狗的图片,即使它看起来很奇怪。 哈哈!这是一条奇怪的狗,不是吗? 您的DataMarking
表中似乎需要一个z-index
(int) 列。此属性充当深度。所以eyeshadow
z-index
例如可以是1,streaks
z-index
可以是5。z-index
越高,标记越晚绘制,导致streaks
被绘制在一切之上。检索到标记数组后,按z-index
升序排列。然后遍历它并绘制所有标记。
您似乎有很多不同的数据数组需要合并到一个数组中
如果您的代码有效,您应该考虑在CodeReview 上发布此问题;对于 *** 而言,这个问题的答案可能过于宽泛或冗长。
【参考方案1】:
以下是对您的代码的一些优化,内联有 cmets 来描述所做的工作。这显然还没有完成,因为 Marcin 在他的回答中指出了一些更好的东西。
// Determine number of markings
$num = mt_rand(1,10);
// Removed redundent $num > X as the conditions were already meet that it was > X by the previous if statement
if ($num == 1)
$markingNum = 0;
else if ($num < 4)
$markingNum = 1;
else if ($num < 6)
$markingNum = 2;
else if ($num < 8)
$markingNum = 3;
else if ($num < 10)
$markingNum = 4;
else
$markingNum = 5;
// Calculate Marking type and color
$markings = array();
if ($markingNum > 0)
for ($m = 1 ; $m <= $markingNum; $m++) // incrimented to 1 and <= so we can dynamically select elements
// Set color values (pulls from the "pallet" selected earlier in the code, which will determine the range of color that marking can be)
$pal = $pallet->'marking' . $m; // Removed if/else and replaced with a dynamic variable
// Uncommon marking (10% chance)
$r = mt_rand(1, 10);
// removed duplicate database selections for a simple $rarity variable that accomplishes the same task
if ($r == 10)
$rarity = 1;
else
$rarity = 0;
$marking = DataMarking::where('rarity', $rarity)
->where('public', 1)
->whereNotIn('name', array_keys($markings))
->whereNotIn('region', $regions)
->orderByRaw("RAND()")
->first();
// Colors marking
if ($pal == 0)
$markingColor = rand_color();
else
$range = ColorRange::where('id', $pal)->firstOrFail();
$markingColor = "#" . mixRange(substr($range->start_hex, 1), substr($range->end_hex, 1));
$markings[$marking->name] = $marking; // adds all of the marking data, this is where you could have a z-index in the database
$markings[$marking->name] = $markingColor; // add your color to your marking data
$regions[] = $marking->region;
【讨论】:
【参考方案2】:我不会回答你的问题,但是看看你的代码有很大的改进空间。
考虑一下:
if ($m == 1)
$pal = $pallet->marking1;
elseif ($m == 2)
$pal = $pallet->marking2;
elseif ($m == 3)
$pal = $pallet->marking3;
elseif ($m == 4)
$pal = $pallet->marking4;
else
$pal = $pallet->marking5;
它可以更改为更简单的东西:
$pa1 = (in_array($m,range(1,4))) ? $pallet->marking$m : $pallet->marking5;
同样适用于:
if ($r == 10)
$marking = DataMarking::where('rarity', 1)
->where('public', 1)
->whereNotIn('name', array_keys($markings))
->whereNotIn('region', array_keys($regions))
->orderByRaw("RAND()")
->first();
// Common markings
else
$marking = DataMarking::where('rarity', 0)
->where('public', 1)
->whereNotIn('name', array_keys($markings))
->whereNotIn('region', array_keys($regions))
->orderByRaw("RAND()")
->first();
如果可以改写为:
$marking = DataMarking::where('rarity', ($r == 10) ? 1 : 0)
->where('public', 1)
->whereNotIn('name', array_keys($markings))
->whereNotIn('region', array_keys($regions))
->orderByRaw("RAND()")
->first();
当然,由于性能原因,上面的ORDER BY RAND()
可能不是最佳解决方案。
你应该真正关心你的代码和重复的数量,否则你很快就会迷失在你正在做的事情中
【讨论】:
非常感谢您的提示!以上是关于对具有不确定数据的数组进行排序的主要内容,如果未能解决你的问题,请参考以下文章