I am trying to create one array out of the two. Two arrays may be different lengths therefore the combine result should accommodate that and fill gaps with null.
My understanding is to first find a bigger array and loop over that, fill the gaps in the smaller array, and once that is done, merge it.
This is what I have done so far, but it feels very clunky, to the point I am starting to think - there must be a better way - less loops and maybe use some of the php array helpers methods ?
<?php
$result_keys = [];
$result_data = [];
$bigger = null;
$smaller = null;
$array1 = [
[
'dog' => 2,
'cat' => 3,
],
[
'dog' => 4,
'cat' => 2,
],
[
'dog' => 2,
'cat' => 3
]
];
$array2 = [
[
'bird' => 7,
],
[
'bird' => 5
]
];
// find which array is bigger
if (count($array1) >= count($array2)) {
$bigger = $array1;
$smaller = $array2;
} else {
$bigger = $array2;
$smaller = $array1;
};
// loop over bigger array
foreach ($bigger as $i => $record) {
foreach ($record as $key => $value) {
if ($i === 0) {
$result_keys[] = $key;
};
$result_data[$i][] = $value;
}
// fill gaps in smaller array
if (!isset($smaller[$i])) {
foreach ($smaller[$i-1] as $key => $value) {
$smaller[$i][$key] = null;
}
}
};
// loop over smaller array
foreach ($smaller as $i => $record) {
foreach ($record as $key => $value) {
if ($i === 0) {
$result_keys[] = $key;
};
$result_data[$i][] = $value;
}
};
var_dump($result_keys);
var_dump($result_data);
// // expected result
// $result_keys = ['dog', 'cat', 'bird'];
// $result_data = [
// [2,3,7],
// [4,2,5],
// [2,3,null]
// ];
My solution to your problem:
$array1 = [
[
'dog' => 2,
'cat' => 3,
],
[
'dog' => 4,
'cat' => 2,
],
[
'dog' => 2,
'cat' => 3
]
];
$array2 = [
[
'bird' => 7,
],
[
'bird' => 5
]
];
// get the number of values of the biggest array
$count = $count = count($array1) >= count($array2) ? count($array1) : count($array2);
$values = [];
$keys = [];
for ($i = 0; $i < $count; $i++) {
$a1 = $array1[$i] ?? [];
$a2 = $array2[$i] ?? [];
$keys = array_unique(array_merge($keys, array_keys($a1), array_keys($a2)));
$values[] = array_values(array_merge(array_fill_keys($keys, null), $a1, $a2));
}
print_r($keys);
print_r($values);
Results (test here):
Array
(
[0] => dog
[1] => cat
[2] => bird
)
Array
(
[0] => Array
(
[0] => 2
[1] => 3
[2] => 7
)
[1] => Array
(
[0] => 4
[1] => 2
[2] => 5
)
[2] => Array
(
[0] => 2
[1] => 3
[2] =>
)
)
Related
I have an array like so
$dataArray = array(
array( 20800, 21679, 0 ),
array( 15254, 0, 3726 ),
array( 17426, 2973, 0 ),
array( 4391, 37, 0 ),
array( 39194, 435, 0 )
);
I am creating a sub array from this. Any value greater than 2000 becomes a 1, otherwise it becomes a 0.
foreach ($dataArray as $row => $data) {
foreach ($data as $key => $value) {
if($value > 1999) {
$dataArray[$row][$key] = 1;
} else {
$dataArray[$row][$key] = 0;
}
}
}
This produces the following
$dataArray = array(
array( 1, 1, 0 ),
array( 1, 0, 1 ),
array( 1, 1, 0 ),
array( 1, 0, 0 ),
array( 1, 0, 0 )
);
Now what I am trying to do is produce another array that shows the positions of the 1's within the above array. Each row should be represented by a new array. The output I am looking for is this
$dataArray = array(
array( 1, 2 ),
array( 1, 3 ),
array( 1, 2 ),
array( 1 ),
array( 1 )
);
So I can see that row 1 has a 1 in position 1 and 2, row 2 has a 1 in positions 1 and 3 etc.
I wanted to make use of my current loop, so I am trying something like this
$position = array();
foreach ($dataArray as $row => $data) {
foreach ($data as $key => $value) {
if($value > 1999) {
$position[$row] = $key + 1;
$dataArray[$row][$key] = 1;
} else {
$dataArray[$row][$key] = 0;
}
}
}
But this seems way off according to my output. How can I achieve what I am after?
Thanks
<?php
$dataArray = array(
array( 20800, 21679, 0 ),
array( 15254, 0, 3726 ),
array( 17426, 2973, 0 ),
array( 4391, 37, 0 ),
array( 39194, 435, 0 )
);
$endResult = [];
foreach ($dataArray as $key => $value) {
foreach ($value as $subkey => $subvalue) {
if ($subvalue >= 2000) {
$endResult[$key][] = $subkey +1;
}
}
}
print_r($endResult);
Array
(
[0] => Array
(
[0] => 1
[1] => 2
)
[1] => Array
(
[0] => 1
[1] => 3
)
[2] => Array
(
[0] => 1
[1] => 2
)
[3] => Array
(
[0] => 1
)
[4] => Array
(
[0] => 1
)
)
You could use array_map along with array_keys:
$dataArray = [
[1, 1, 0],
[1, 0, 1],
[1, 1, 0],
[1, 0, 0],
[1, 0, 0]
];
$onePositions = array_map(function($row) {
return array_map(function($position) { return $position + 1; }, array_keys($row, 1));
}, $dataArray);
echo '<pre>'; var_dump($onePositions); echo '</pre>';
Demo here
You can make use of the second parameter in the array_keys() function to get the positions after you populate the ones and zeros:
$position = array();
$binary = array();
foreach ($dataArray as $row => $data) {
// if you want to have the positions start at 1 instead of 0
// add a dummy value to the final array
$binary[$row][] = 0;
foreach ($data as $key => $value) {
if($value > 1999) {
$binary[$row][] = 1;
} else {
$binary[$row][] = 0;
}
}
$positions[] = array_keys($binary[$row], 1);
}
Demo Here
<?php
$teams = [0 => ['players' => ['marie'=>2342,
'paul'=>3632,
'vincent'=>2362,
'pierre'=>7823,
'jean'=>9203]
],
1 => ['players' => []
],
2 => ['players' => []
],
3 => ['players' => []
]
];
$all_teams = array_merge($teams[0]['players'],
$teams[1]['players'],
$teams[2]['players'],
$teams[3]['players']);
$result = array_chunk($all_teams, 1, true);
for ($i = 0; $i <= 3; $i++) {
if (isset($result[$i]) && isset($teams[$i])) {
$teams[$i]['players'] = $result[$i];
}
}
//I want a input of array like
$teams = [0 => ['players' => ['marie'=>2342, 'jean'=>9203]
],
1 => ['players' => ['paul'=>3632]
],
2 => ['players' => ['vincent'=>2362]
],
3 => ['players' => ['pierre'=>7823]
]
];
Hello, I want to add each player on each team to balance the arrays;
the problem with my code, it puts it in the mess and 'jean' does not count in the array and i want the last element to be added too. and find a better way to balance the tables for each incoming element.
You can do something like:
$teams = [0 => ['players' => ['marie'=>2342,'paul'=>3632,'vincent'=>2362,'pierre'=>7823,'jean'=>9203]],
1 => ['players' => []],
2 => ['players' => []],
3 => ['players' => []]
];
//Get all players and put them into a single array
$players = array_reduce(array_column( $teams, 'players' ),'array_merge',array());
$teamCount = count($teams);
//Clear all Teams
foreach($teams as $key => $team) {
$teams[$key]['players'] = array();
}
//Assign the playes to the team using mod
foreach(array_keys($players) as $key => $player ) {
$teams[ $key % $teamCount ]['players'][$player] = $players[$player];
}
This will result to:
Array
(
[0] => Array
(
[players] => Array
(
[marie] => 2342
[jean] => 9203
)
)
[1] => Array
(
[players] => Array
(
[paul] => 3632
)
)
[2] => Array
(
[players] => Array
(
[vincent] => 2362
)
)
[3] => Array
(
[players] => Array
(
[pierre] => 7823
)
)
)
Here is a solution. It counts total players and then redistributes according to how many players you want on a team.
function balanceTeams($teams, $playersPerTeam, $shuffle = NULL){
//Get total players in array
$playerCount = 0;
foreach($teams as $team){
foreach($team['players'] as $player=>$id){
$players[] = array('name' => $player, 'id'=>$id);
}
}
$playerCount = count($players);
if($shuffle){
shuffle($players);
}
//Make your new array
$count = 0;
$team = 0;
for($i = 0; $i < $playerCount; $i += $playersPerTeam){
for($j = 0; $j < $playersPerTeam; $j++){
if($players[$count]['id']){
$results[$team]['players'][$players[$count]['name']] = $players[$count]['id'];
}else {
break;
}
$count++;
}
$team++;
}
return $results;
}
How to use:
$teams = [0 => ['players' => ['marie'=>2342,
'paul'=>3632,
'vincent'=>2362,
'pierre'=>7823,
'jean'=>9203]
],
1 => ['players' => []
],
2 => ['players' => []
],
3 => ['players' => []
]
];
$playersPerTeam = 2;
$shuffle = NULL; //Set to 1 to shuffle.
$results = balanceTeams($teams, $playersPerTeam, $shuffle);
print_r($results);
Outputs:
Array
(
[0] => Array
(
[players] => Array
(
[marie] => 2342
[paul] => 3632
)
)
[1] => Array
(
[players] => Array
(
[vincent] => 2362
[pierre] => 7823
)
)
[2] => Array
(
[players] => Array
(
[jean] => 9203
)
)
)
function:
function mixPlayers($teams)
{
$r = [];
array_walk_recursive($teams, function ($v, $k) use (&$r) {
if (!is_array($v)) {
$r[] = [$k => $v];
}
});
return $r;
}
function assign($players, $need)
{
$res = [];
for ($i = 0; $i < count($players); $i++) {
$index = $i % $need;
$res[$index]['players'] = array_merge(
isset($res[$index]['players']) ? $res[$index]['players'] : [],
$players[$i]
);
}
return $res;
}
usage:
$res = assign( mixPlayers($teams) , 4);
var_export($res);
Array
[0] => Array
(
[a1] => 12
[v1] => 3100.00
[v2] => 186.00
[v3] => 186.00
)
[1] => Array
(
[a1] => 12
[v1] => 1200.00
[v2] => 72.00
[v3] => 72.00
)
i want to create new array from this array
which is look like this as given below it should give me '12' common and add other values
Array
[0] => Array
(
[a1] => 12
[v1] => 4300.00
[v2] => 258.00
[v3] => 258.00
)
Try This code ,
foreach($value as $i=>$v) {
$temp[0]['a1'] = $v['a1'];
$temp[0]['v1'] += $v['v1'];
$temp[0]['v2'] += $v['v2'];
$temp[0]['v3'] += $v['v3'];
}
Please find below code:
<?php
$merged = array();
$res = array('a1'=>12,'v1'=>3100.00,'v2'=>186.00,'v3'=>186.00);
$res1 = array('a1'=>12,'v1'=>1200.00,'v2'=>72.00,'v3'=>72.00);
foreach ([$res, $res1] as $a) { // iterate both arrays
foreach ($a as $key => $value) { // iterate all keys+values
$merged[$key] = $value + (isset($merged[$key]) ? $merged[$key] : 0); // merge and add
}
}
print "<pre>";
print_r($merged);
die;
?>
It's a bit unclear the real your needs, so this solution only one of a few possible solutions.
This script a1 element is using as key, so it will work with more than one a1 value.
Example:
<?php
$a = [
[
'a1' => 12,
'v1' => 3100.00,
'v2' => 186.00,
'v3' => 186.00,
],
[
'a1' => 12,
'v1' => 1200.00,
'v2' => 72.00,
'v3' => 72.00,
],
[
'a1' => 13,
'v1' => 2100.00,
'v2' => 386.00,
'v3' => 386.00,
],
[
'a1' => 13,
'v1' => 1200.00,
'v2' => 72.00,
'v3' => 72.00,
]
];
$r = [];
foreach ($a as $item) {
$key = $item['a1'];
if (empty($r[$key]))
$r[$key] = $item;
else {
foreach ($item as $k => $v) {
if ($k !== 'a1')
$r[$key][$k] = empty($r[$key][$k]) ? $item[$k] : $r[$key][$k] + $item[$k];
}
}
}
print_r(array_values($r));
A simple foreach loop can do it.
$result = array();
foreach($yourArray as $arr){
foreach($arr as $i=>$v) {
if(!isset($result[$i])) {
$result[$i] = 0;
}
if($i == 'a1'){
$result[$i] = $v;
} else {
$result[$i] += $v;
}
}
}
I have multi-dimensional array:
$array = array(
array(
"id" => 1,
"value" => 100
),
array(
"id" => 1,
"value" => 200
),
array(
"id" => 1,
"value" => 300
),
array(
"id" => 2,
"value" => 2
),
array(
"id" => 2,
"value" => 5
),
array(
"id" => 3,
"value" => 10.50
),
);
I need to get new multi-dimensional array, like this:
$newArray = array(
array(
"id" => "1",
"sum_of_values" => 600
),
array(
"id" => 2,
"sum_of_values" => 7
),
array(
"id" => 3,
"sum_of_values" => 10.50
),
);
I mean, key [sum_of_values] should counts values in sub-arrays with the same key [id].
I've tried this:
$cnt = count($array);
$finalArray = array();
$tempArray = array();
for($i = 0; $i < $cnt; $i++){
if($array[$i]["id"] == $array[$i++]["id"]){
$search = $array[$i]["id"];
$column = "value";
$sum = array_sum(
array_map(
function($data) use ($column) {
return $data[$column];
},
array_filter(
$array,
function($data) use ($search) {
return fnmatch($search, $data["id"]);
}
)
)
);
$tempArray = array(
"id" => $array[$i]["id"],
"sum_of_values" => $sum
);
$finalArray[] = $tempArray;
} else {
$tempArray = array(
"id" => $array[$i]["id"],
"sum_of_values" => $array[$i]["value"]
);
}
}
And it works, it counts values of sub-arrays with same [id]. But the problem is not returning sub-arrays, key [id] of which doesn't have same examples. In my case - sub-array with [id] = 3 will not return. Also, sub-arrays with [id] = 1 and [id] = 2 will repeat [n-n/2] times.
I think, that problem is in using cycle - for ($i = 0; $i < $cnt; $i++) and condition if ($array[$i]["id"] == $array[$i++]["id"]), because it looks stupid, but i can't find anything else.
Your function seems too complicated. How about this?
$result = array();
foreach ($array as $item) {
if (!empty($result[$item['id']]))
$result[$item['id']]['sum_of_values'] += $item['value'];
else
$result[$item['id']] = array(
'id' => $item['id'],
'sum_of_values' => $item['value']
);
}
If you print_r($result) you get:
Array
(
[1] => Array
(
[id] => 1
[sum_of_values] => 600
)
[2] => Array
(
[id] => 2
[sum_of_values] => 7
)
[3] => Array
(
[id] => 3
[sum_of_values] => 10.5
)
)
Just as an alternative: this is a sitter for array_reduce():
$totals = array_reduce($array, function($reduction, $current){
$id = $current["id"];
if (empty($reduction[$id])){
$reduction[$id] = ["id"=>$id, "sum_of_values"=>0];
}
$reduction[$id]["sum_of_values"] += $current["value"];
return $reduction;
}, []);
I prefer this sort of approach to generic looping/processing: I think it's a bit cleaner. But mileage varies, obviously.
i want to compare 2 arrays. If a value from $a ist found is $b there should be make a new value in $a like [found] => true.
Array $a:
Array
(
[1] => Array
(
[grpID] => 1
[groupname] => Marketing
)
[2] => Array
(
[grpID] => 2
[groupname] => Vertrieb
)
[4] => Array
(
[grpID] => 4
[groupname] => Produktion
)
)
Array $b:
Array
(
[1] => Array
(
[usrID] => 23
[grpID] => 1
)
)
So now i want to compare these two.
The result should look like the following, because $b[1]['grpID'] was like in $a[1]['grpID']:
Array $c (or $a as manipulated?):
Array
(
[1] => Array
(
[grpID] => 1
[groupname] => Marketing
[found] => true
)
[2] => Array
(
[grpID] => 2
[groupname] => Vertrieb
[found] => false
)
)
The size of $b may vary so i don't think i can work with a for-loop, can i?
Sorry, i've got no code so far as i don't have an idea how to start.
Thanks in advance.
Best regards
Do it with an temporary array $temp.
$a = array();
$b = array();
$c = array();
$tmp = array();
$a[1] = array('grpID' => 1, 'groupname' => 'Marketing');
$a[2] = array('grpID' => 2, 'groupname' => 'Vertrieb');
$a[4] = array('grpID' => 4, 'groupname' => 'Produktion');
$b[1] = array('usrID' => 23, 'grpID' => 1);
foreach ($b as $key => $value) {
$tmp[] = $value['grpID'];
}
foreach ($a as $key => $value) {
$c[] = array_merge($value, array('found' => (in_array($value['grpID'], $tmp) ? 'true' : false)));
}
Checkout the following code
<?php
$a = array(
array(
'grpID' => 1,
'groupname' => 'Marketing'
),
array(
'grpID' => 2,
'groupname' => 'Vertrieb'
),
array(
'grpID' => 5,
'groupname' => 'Produktion'
)
);
$b = array(
array(
'grpID' => 1,
'usrID' => 23
)
);
$c = array();
for ($i = 0; $i < count($a); $i++)
{
$tmp = $a[$i];
$tmp['found'] = FALSE;
for ($j = 0; $j < count($b); $j++)
{
if ($tmp['grpID'] === $b[$j]['grpID'])
{
$tmp['found'] = TRUE;
break;
}
}
array_push($c, $tmp);
}
// Final output
print_r($c);
?>
There are a few different ways to do this, I toyed with the idea of using array_walk and using a object orientated approach. The way below is the simplest to implement but if I were doing this on a system of my own I would probably go object orientated for cleaner code and better maintenance.
here are the help pages for array_walk http://uk1.php.net/array_walk just in case you wanted to look at another way.
$foundGroups = array();
//set all found values to false
foreach ($a as $group) {
$group['found'] = false;
}
foreach ($b as $user) {
$groupToFind = $user['grpID'];
// This is to limit the number of times we do this, there is no point
// in looking for the same group twice
if (!in_array($groupToFind, $foundGroups)) {
foreach ($a as $group) {
if ($group['grpID'] == $groupToFind) {
$group['found'] = 'true';
$foundGroups[] = $groupToFind;
}
}
}
}