我有一个带有type
属性的多维关联数组。它看起来像这样:
$data = array(
array( "name" => "SomeName", "type" => "A"),
array( "name" => "SomeName", "type" => "A"),
array( "name" => "SomeName", "type" => "A"),
array( "name" => "SomeName", "type" => "A"),
array( "name" => "SomeName", "type" => "A"),
array( "name" => "SomeName", "type" => "B"),
array( "name" => "SomeName", "type" => "B"),
array( "name" => "SomeName", "type" => "B"),
array( "name" => "SomeName", "type" => "C"),
array( "name" => "SomeName", "type" => "C")
);
我想重新排列它以使项目分布更均匀(如果可能,重复类型最少)。它应该是这样的:
array(
array( "name" => "SomeName", "type" => "A"),
array( "name" => "SomeName", "type" => "B"),
array( "name" => "SomeName", "type" => "A"),
array( "name" => "SomeName", "type" => "C"),
array( "name" => "SomeName", "type" => "A"),
array( "name" => "SomeName", "type" => "B"),
array( "name" => "SomeName", "type" => "A"),
array( "name" => "SomeName", "type" => "C"),
array( "name" => "SomeName", "type" => "A"),
array( "name" => "SomeName", "type" => "B")
);
我到目前为止所做的是找到每种类型和总数的计数:
$count_a = 5;
$count_b = 3;
$count_c = 2;
$total = 10;
以及每种类型的比率:
$ratio_a = 0.5; //(5/10)
$ratio_b = 0.3; //(3/10)
$ratio_c = 0.2; //(2/10)
我只是被困在这里。我应该尝试使用数字创建一个新属性index
,然后根据它进行排序吗?或者也许以某种方式使用模运算符?我还尝试将这些项目分成3个不同的数组,如果这样可以更容易。
答案 0 :(得分:7)
这是一种尽可能避免重复模式的解决方案。
对于AAAAABBBCC
,它会生成ABABABACAC
;
对于AAAAABBBCCC
,它会生成ABCABABACAC
;
除了按类型计数排序外,它还以线性时间运行(它接受未排序的数据数组)。结果在$distributed_data
。有关解释,请参阅下文。
$data = array(
array( "name" => "SomeName", "type" => "A"),
array( "name" => "SomeName", "type" => "A"),
array( "name" => "SomeName", "type" => "A"),
array( "name" => "SomeName", "type" => "B"),
array( "name" => "SomeName", "type" => "B"),
);
$distributed_data = array();
$counts = array();
$size = sizeof($data);
// Count values
foreach ($data as $entry) {
$counts[$entry["type"]] = isset($counts[$entry["type"]]) ? $counts[$entry["type"]] + 1 : 1;
}
// Set counter
for ($i = 0; $i < $size; $i++) {
$data[$i]["count"] = $counts[$data[$i]["type"]];
}
// Sort by count
usort($data, function($entry1, $entry2) {
return $entry2["count"] <=> $entry1["count"];
});
// Generate the distributed array
$max_length = $data[0]["count"];
$rows = ceil($size / $max_length);
$last_row = ($size - 1) % $max_length + 1;
$row_cycle = $rows;
$row = 0;
$col = 0;
for ($i = 0; $i < $size; $i++) {
if ($i == $rows * $last_row) {
$row_cycle -= 1;
}
$distributed_data[$i] = $data[$row * $max_length + $col];
$row = ($row + 1) % $row_cycle;
if ($row == 0) {
$col++;
}
}
首先,根据每种类型的重复次数对条目进行排序。例如。 CBBCAAB
变为BBBAACC
。
然后想象一个表中列数最多的表(例如,如果你有AAAABBCC
,最常见的是4,表格将有4列。)
然后将所有条目写入表格,从左到右,根据需要跳转到新行。
E.g。对于AAAAABBBCCC
,你会得到一张这样的表:
要生成最终的分布式数组,只需从上到下读取条目,然后根据需要转移到新列。
在上面的示例中,您将获得ABCABABACAC
。
获得重复条目的唯一方法是在列中包含两个相同的字符,或者在转移到右侧的列时遇到相同的字符。
第一种情况不可能发生,因为角色群需要环绕而且这种情况不会发生,因为没有字符组长于列数(这就是我们的方式)定义了表格。
第二种情况只有在第二行不满时才会发生。例如。 AAAABB
留下第二行有两个空单元格。
答案 1 :(得分:4)
您应该对已排序的类型进行排序,并按顺序逐步更改所选类型。
$data = array(
array( "name" => "SomeName1", "type" => "A"),
array( "name" => "SomeName2", "type" => "A"),
array( "name" => "SomeName3", "type" => "A"),
array( "name" => "SomeName4", "type" => "A"),
array( "name" => "SomeName5", "type" => "A"),
array( "name" => "SomeName6", "type" => "B"),
array( "name" => "SomeName7", "type" => "B"),
array( "name" => "SomeName8", "type" => "B"),
array( "name" => "SomeName9", "type" => "C"),
array( "name" => "SomeName0", "type" => "C")
);
$dataSorted = array();
$counts = array();
foreach($data as $elem) {
// just init values for a new type
if(!isset($counts[$elem['type']])) {
$counts[$elem['type']] = 0;
$dataByType[$elem['type']] = array();
}
// count types
$counts[$elem['type']]++;
// save it to grouped array
$dataByType[$elem['type']][] = $elem;
}
// sort it to A=>5, B=>3 C=>2
arsort($counts, SORT_NUMERIC);
// get sorted types as an array
$types = array_keys($counts);
// index will be looped 0 -> count($types) - 1 and then down to 0 again
$currentTypeIndex = 0;
// make a walk on sorted array. First get the most popular, then less popular etc.
// when all types are added, repeat
while(count($dataSorted) < count($data)) {
$currentType = $types[$currentTypeIndex];
// skip adding if we ran out this type
if($counts[$currentType]) {
// pop an element of selected type
$dataSorted[] = array_pop($dataByType[$currentType]);
// decrease counter
$counts[$currentType]--;
}
// choose next type
$currentTypeIndex = (++$currentTypeIndex)%count($types);
}
print_r($dataSorted);
代码按ABCABCABAA的顺序输出元素。
UPD。在count(maxtype)
&gt;的情况下发生尾随加倍count(nexttype) + 1
答案 2 :(得分:4)
算法:
function distribute($data) {
$groups = [];
foreach ($data as $row) {
$groups[$row['type']][] = $row;
}
$groupSizes = array_map('count', $groups);
asort($groupSizes);
$result = [];
foreach ($groupSizes as $type => $groupSize) {
if (count($result) == 0) {
$result = $groups[$type];
} elseif (count($result) >= count($groups[$type])) {
$result = merge($result, $groups[$type]);
} else {
$result = merge($groups[$type], $result);
}
}
return $result;
}
function merge($a, $b) {
$c1 = count($a);
$c2 = count($b);
$result = [];
$i1 = $i2 = 0;
while ($i1 < $c1) {
$result[] = $a[$i1++];
while ($i2 < $c2 && ($i2+1)/($c2+1) < ($i1+1)/($c1+1)) {
$result[] = $b[$i2++];
}
}
return $result;
}
主要思想是将数据拆分成组并将下一个最小的组合并到结果中(从空结果开始)。
在合并两个数组时,项目按浮动键排序,浮点键在此行中计算(在流程上)
while ($i2 < $c2 && ($i2+1)/($c2+1) < ($i1+1)/($c1+1))
作为
floatKey = (index + 1) / (groupSize + 1)
(但这部分可以改进,因此与角落的距离为0
和1
),这两个角落的距离是两个项目之间的距离的一半。
首先是来自较大群体的项目。
示例:合并AAAA
和BB
A
的密钥为0.2, 0.4, 0.6, 0.8
- B
0.33, 0.66
。结果将是
A(0.2), B(0.33), A(0.4), A(0.6), B(0.66), A(0.8)
试验:
$testData = [
'AAAAABBBCC',
'AAAAABBBCCC',
'ABBCCC',
'AAAAAABBC',
'AAAAAABBBBCCD',
'AAAAAAAAAABC',
'hpp',
'stackoverflow',
'ACCD', // :-)
];
$results = [];
foreach ($testData as $dataStr) {
$a = str_split($dataStr);
$data = [];
foreach ($a as $type) {
$data[] = ['type' => $type];
}
$result = distribute($data);
$resultStr = implode(array_column($result, 'type'));
$results[$dataStr] = $resultStr;
}
var_export($results);
测试结果:
'AAAAABBBCC' => 'BACABACABA',
'AAAAABBBCCC' => 'CABACABACAB',
'ABBCCC' => 'BCACBC',
'AAAAAABBC' => 'ABAACAABA',
'AAAAAABBBBCCD' => 'BACABADABACAB',
'AAAAAAAAAABC' => 'AAACAAAABAAA',
'hpp' => 'php',
'stackoverflow' => 'sakeofwlrovct',
'ACCD' => 'ACDC',
测试演示:http://rextester.com/BWBD90255
您可以轻松地向演示中添加更多测试用例。
答案 3 :(得分:3)
$data = array(
array( "name" => "SomeName", "type" => "A"),
array( "name" => "SomeName", "type" => "A"),
array( "name" => "SomeName", "type" => "A"),
array( "name" => "SomeName", "type" => "A"),
array( "name" => "SomeName", "type" => "A"),
array( "name" => "SomeName", "type" => "B"),
array( "name" => "SomeName", "type" => "B"),
array( "name" => "SomeName", "type" => "B"),
array( "name" => "SomeName", "type" => "C"),
array( "name" => "SomeName", "type" => "C")
);
//make seperate arrays
echo "<pre>";
foreach($data as $val){
${$val["type"]}[]=$val["name"];
$types[]=$val['type'];
}
$types=array_unique($types);
//make ratio
foreach($types as $val){
$cnt[]=count($$val);
}
//find maximum from ratio
echo $max=max($cnt);
echo $min=min($cnt);
for($i=0;$i<$max;$i++){
foreach($types as $val){
if(isset($$val[$i])){
$new_array[]=array("name"=>$$val[$i],"type"=>$val);
}
}
}
print_r($new_array);
小提琴:http://phpfiddle.org/main/code/ju2k-abte
解释
- Step 1: Make separate array - Step 2: Count all array and find out the ratio - Step 3: Iterate with array with maximum ratio value - Step 4: Make array with same index together and merge them in multidimensional array
答案 4 :(得分:2)
检查您想要的确切输出
$data = array(
array("name" => "SomeName", "type" => "A"),
array("name" => "SomeName1", "type" => "A"),
array("name" => "SomeName2", "type" => "A"),
array("name" => "SomeName3", "type" => "A"),
array("name" => "SomeName4", "type" => "A"),
array("name" => "SomeName5", "type" => "B"),
array("name" => "SomeName6", "type" => "B"),
array("name" => "SomeName7", "type" => "B"),
array("name" => "SomeName8", "type" => "C"),
array("name" => "SomeName9", "type" => "C"),
);
// getting all counts
$type = [];
foreach ($data as $key => $value) {
if (empty($type) || $type != $value['type']) {
$type = $value['type'];
$counter = 0;
}
$temp[$value['type']] = ++$counter;
}
/**
* array search with multiple values
*
* @param array $parents input array
* @param array $searched search array
*
* @return int key of found items
*/
function multidimensional_search($parents, $searched)
{
if (empty($searched) || empty($parents)) {
return false;
}
foreach ($parents as $key => $value) {
$exists = true;
foreach ($searched as $skey => $svalue) {
$exists = ($exists && isset($parents[$key][$skey]) && $parents[$key][$skey] == $svalue);
}
if ($exists) {return $key;}
}
return false;
}
$output_array = [];
$first_value = current($temp);
$first_key = key($temp);
$flag = 0;
$junkArr = array_column($data, 'type', 'name');
$remember_me = 0;
$incr = 0;
end($temp);
$end_item = key($temp);
reset($temp);
$remember_index = 0;
for ($i = 0; $i < count($data); $i++) {
$output_array[] = $data[multidimensional_search($data, ['name' => key($junkArr), 'type' => current($junkArr)])];
if ($temp[$first_key] > 0) {
$temp[$first_key] = --$first_value;
}
$direction = (empty($direction) || $direction == 'reverse' ? "forward" : "reverse");
for ($k = 0; $k <= $remember_me; $k++) {
if ($direction == 'forward') {
next($temp);
} else {
prev($temp);
if ($k == 0) {
$incr = $remember_me + 1;
}
}
}
$remember_me = $incr;
if ($remember_me == count($temp) - 1) {
$remember_me = 0;
}
$first_key = key($temp);
$first_value = current($temp);
if (in_array($first_key, $junkArr)) {
$saved_key = key($junkArr);
reset($junkArr);
while ($first_key !== current($junkArr)) {
next($junkArr);
}
unset($junkArr[$saved_key]);
}
}
pr($output_array);
die;
以您喜欢的方式映射。
尝试一下,它会起作用。
我想做的是,
答案 5 :(得分:2)
你可以这样使用
{project}\obj\local\armeabi\
谢谢,
答案 6 :(得分:0)
如果您想要的是重新排序列表以最小化重复次数,那么一旦您拥有每种类型的计数,例如
$count_a = 5;
$count_b = 3;
$count_c = 2;
$total = 10;
然后您可以选择人口最多的类型,并从该类型中选择一行,并将其放在您正在创建的列表中的第0位。然后减少该类型的计数,并从未选择的人口最多的类型中进行选择。继续,直到只剩下一种类型,并将它们放在列表的末尾。
答案 7 :(得分:0)
这是基于naktinis's great answer上的想法的另一个实现:
// split data into arrays of distinct type
$buckets = array_reduce($data, function($result, $item) {
$type = $item["type"];
if (!isset($result[$type])) {
$result[$type] = [];
}
array_push($result[$type], $item);
return $result;
}, []);
// sort buckets by size
usort($buckets, function($a, $b) {
return count($b) - count($a);
});
// merge buckets to single array sorted by type
// and split to chunks of size of the largest bucket
$table = array_chunk(array_merge(...$buckets), count($buckets[0]));
// compute final array by merging each column
$result = [];
foreach (array_keys($table[0]) as $i) {
$result = array_merge($result, array_column($table, $i));
}
答案 8 :(得分:0)
/**
* Create login session
* */
public void createLoginSession(String username, String accesstoken,String tokentype, String masterid,String name, Integer access){
// Storing login value as TRUE
editor.putBoolean(IS_LOGIN, true);
editor.putString(KEY_USERNAME, username);
// Storing name in pref
editor.putString(KEY_access_token, accesstoken);
// Storing email in pref
editor.putString(KEY_TOKEN_TYPE, tokentype);
editor.putString(KEY_MASTER_ID, masterid);
editor.putString(KEY_TOKEN_TYPE, tokentype);
editor.putString(KEY_NAME, name);
editor.putInt(KEY_Access, access);
// commit changes
editor.commit();
String user_name_new=pref.getString(KEY_USERNAME, null)
Log.d("TAG","Pass user name :"+username+" user_name_new:"+user_name_new);
}
感谢:)
答案 9 :(得分:0)
OMG 这里有很多巨大的功能。
要求ABAC ABAC ...... 完成:
function sortTypes(array $data, array $types)
{
$result = [];
while (!empty($data)) {
$currentType = current($types);
if (!next($types)) {
reset($types);
}
foreach ($data as $key => $array) {
if ($array['type'] === $currentType) {
$result[$key] = $array;
unset($data[$key]);
break;
}
}
}
return $result;
}
$types = ['A', 'B', 'A', 'C']; // gets sorted by this pattern
$result = sortTypes($data, $types);
测试:
var_export($result);
// OUT:
[
0 => [
'name' => 'SomeName',
'type' => 'A',
],
5 => [
'name' => 'SomeName',
'type' => 'B',
],
1 => [
'name' => 'SomeName',
'type' => 'A',
],
8 => [
'name' => 'SomeName',
'type' => 'C',
],
2 => [
'name' => 'SomeName',
'type' => 'A',
],
6 => [
'name' => 'SomeName',
'type' => 'B',
],
3 => [
'name' => 'SomeName',
'type' => 'A',
],
9 => [
'name' => 'SomeName',
'type' => 'C',
],
4 => [
'name' => 'SomeName',
'type' => 'A',
],
7 => [
'name' => 'SomeName',
'type' => 'B',
],
]