I have sorted a multidimensional array on value distance from low to high. This is an example of the output: (the actual output has around 20 or 30 arrays).
Array
(
[0] => Array
(
[id] => 1
[distance] => 5
[sponsor] => 0
)
[1] => Array
(
[id] => 20
[distance] => 8
[sponsor] => 1
)
[2] => Array
(
[id] => 25
[distance] => 10
[sponsor] => 0
)
[3] => Array
(
[id] => 78
[distance] => 25
[sponsor] => 1
)
)
After sorting on distance from low to high, I want to give priority if sponsor = 1. This is the preferred output:
Array
(
[0] => Array
(
[id] => 20
[distance] => 8
[sponsor] => 1
)
[1] => Array
(
[id] => 78
[distance] => 25
[sponsor] => 1
)
[2] => Array
(
[id] => 1
[distance] => 5
[sponsor] => 0
)
[3] => Array
(
[id] => 25
[distance] => 10
[sponsor] => 0
)
)
Sponsor is either 0 or 1. How can I tackle this problem? I was thinking of, before sorting on distance, I should split up the array in 2 arrays based on sponsor (0,1), sort both arrays on distance, and then merge them with sponsor=1 at the top of the new multidimensional array. Is this the way to do it?
Thank you for your input.
This is slightly modified version of what usort suggests. Assuming source array is called $arr:
usort(
$arr, function($a, $b) {
if ( $a['sponsor'] == $b['sponsor'] ) {
if ( $a['distance'] == $b['distance'] ) {
return 0;
}
return $a['distance'] < $b['distance'] ? -1 : 1;
}
return $a['sponsor'] > $b['sponsor'] ? -1 : 1;
}
);
You have to split original array to 2 arrays: 1st has sponsor=1, 2nd has sponsor=0. Then sort them separately and merge.
Somehow like this:
$array1 = array_filter($array, function ($v) { return $v['sponsor'] == 1; });
$array2 = array_filter($array, function ($v) { return $v['sponsor'] == 0; });
function cmp($a, $b) {
return $a['distance'] < $b['distance']? -1 : 1;
}
usort($array1, cmp);
usort($array2, cmp);
$result = array_merge($array1, $array2);
You can use array_multisort() function to achieve what you want:
<?php
$arr = [
['id' => 1, 'distance' => 5, 'sponsor' => 0],
['id' => 20, 'distance' => 8, 'sponsor' => 1],
['id' => 25, 'distance' => 10, 'sponsor' => 0],
['id' => 78, 'distance' => 25, 'sponsor' => 1],
];
$sponsor = array_column($arr, 'sponsor');
$distance = array_column($arr, 'distance');
// rearrange $arr by sponsor DESC and then by distance ASC
array_multisort($sponsor, SORT_DESC, $distance, SORT_ASC, $arr);
print_r($arr);
That would work but if you use a stable sorting algorithm then you can sort first by distance, then by sponsor descending and you will get your desired results.
Try This :
<?php
$ar = array(
array("10", 11, 100, 100, "a"),
array( 1, 2, "2", 3, 1)
);
array_multisort($ar[0], SORT_ASC, SORT_STRING,
$ar[1], SORT_NUMERIC, SORT_DESC);
var_dump($ar);
?>
or
<?php
$ar1 = array(10, 100, 100, 0);
$ar2 = array(1, 3, 2, 4);
array_multisort($ar1, $ar2);
var_dump($ar1);
var_dump($ar2);
?>
Related
I have an array with the following structure:
[0] => Array
(
[venue1] => 1
[venue2] => 2
)
[1] => Array
(
[venue1] => 3
[venue2] => 4
)
[2] => Array
(
[venue1] => 2
[venue2] => 1
)
[3] => Array
(
[venue1] => 5
[venue2] => 6
)
I need to remove the duplicate "pair of values", in this case row [0] and row [2]
I tried it with that code, but it doesn't work (and of course it's not very elegant) ;-)
foreach ( $compare_arr as $v1 )
{
$key = array_search( intval($v1[venue1]), array_column( $compare_arr, 'venue2' ) );
if ( $key <> '' ) unset($compare_arr[$key]);
}
Do you have an idea how to solve this?
Thanks a lot for your help!
Oliver
Here is an approach where an intermediate array is formed of sorted values. That you can then search for to find duplicate pairs to remove.
<?php
$venues =
array (
0 =>
array (
'venue1' => 1,
'venue2' => 2,
),
1 =>
array (
'venue1' => 3,
'venue2' => 4,
),
2 =>
array (
'venue1' => 2,
'venue2' => 1,
),
3 =>
array (
'venue1' => 5,
'venue2' => 6,
),
);
$result = $pairs = $venues;
array_walk($pairs, 'sort');
var_export($pairs);
foreach($pairs as $k => $pair) {
if(count(array_keys($pairs, $pair)) > 1) {
unset($result[$k]);
}
}
var_export($result);
Output:
array (
0 =>
array (
0 => 1,
1 => 2,
),
1 =>
array (
0 => 3,
1 => 4,
),
2 =>
array (
0 => 1,
1 => 2,
),
3 =>
array (
0 => 5,
1 => 6,
),
)array (
1 =>
array (
'venue1' => 3,
'venue2' => 4,
),
3 =>
array (
'venue1' => 5,
'venue2' => 6,
),
)
If you want to remove occurring duplicates rather than pruning out duplicates altogether, you can do an array_unique on the sorted array above and then use the remaining keys to filter the original array.
$tmp = $venues;
array_walk($tmp, 'sort');
$tmp = array_unique($tmp, SORT_REGULAR);
$result = array_intersect_key($venues, $tmp);
var_export($result);
Output:
array (
0 =>
array (
'venue1' => 1,
'venue2' => 2,
),
1 =>
array (
'venue1' => 3,
'venue2' => 4,
),
3 =>
array (
'venue1' => 5,
'venue2' => 6,
),
)
You might also first loop the array creating a compound key based on the ordered keys.
Then you can filter the result only keeping arrays where the count is 2 as nothing is added because there are no duplicates.
For example
$result = [];
$compare_arr = [
["venue1" => 1, "venue2" => 2],
["venue1" => 3, "venue2" => 4],
["venue1" => 2, "venue2" => 1],
["venue1" => 5, "venue2" => 6],
];
foreach ($compare_arr as $v1) {
sort($v1);
$cKey = $v1[0] .'-'. $v1[1];
if (array_key_exists($cKey, $result)) {
$result[$cKey][] = $v1;
continue;
}
$result[$cKey] = $v1;
}
$result = array_filter($result, function($item) {
return count($item) === 2;
});
print_r($result);
Output
Array
(
[3-4] => Array
(
[0] => 3
[1] => 4
)
[5-6] => Array
(
[0] => 5
[1] => 6
)
)
You can see the compound keys are the values with a - in between. If you want to have the keys numbered from 0, you can use array_values.
Php demo
Edit
If you want to keep the first matching single pair, you can check for the compound key and if it already exists continue the loop without overwriting the existing one.
$result = [];
$compare_arr = [
["venue1" => 1, "venue2" => 2],
["venue1" => 3, "venue2" => 4],
["venue1" => 2, "venue2" => 1],
["venue1" => 5, "venue2" => 6]
];
foreach ($compare_arr as $v1) {
sort($v1);
$cKey = $v1[0] .'-'. $v1[1];
if (array_key_exists($cKey, $result)) {
continue;
}
$result[$cKey] = $v1;
}
print_r($result);
Output
Array
(
[1-2] => Array
(
[0] => 1
[1] => 2
)
[3-4] => Array
(
[0] => 3
[1] => 4
)
[5-6] => Array
(
[0] => 5
[1] => 6
)
)
Php demo
Whether you use a classic foreach() loop or functional iteration, there is no reason to iterate the input array more than once.
This snippet will appear nearly identical to TheFourthBird's answer, but I don't like the unnecessary use of continue. This snippet will ensure no that rows in the result array have 100% shared venue values (in any order). The subarray keys will also not suffer reordering; in other words the first element key will be venue1 then the second element will be venue2. Using implode() offers additional flexibility because the code won't need to be altered if the number of elements in each row changes.
$result = [];
foreach ($data as $index => $row) {
sort($row);
$key = implode('-', $row);
if (!isset($result[$key])) {
$result[$key] = $data[$index];
}
}
var_export(array_values($result));
Output:
array (
0 =>
array (
'venue1' => 1,
'venue2' => 2,
),
1 =>
array (
'venue1' => 3,
'venue2' => 4,
),
2 =>
array (
'venue1' => 5,
'venue2' => 6,
),
)
To completely remove all rows where venue values are shared, maintain a "found" array as well as a "result" array.
Code: (Demo)
$result = [];
foreach ($data as $index => $row) {
sort($row);
$key = implode('-', $row);
if (!isset($found[$key])) {
$found[$key] = true;
$result[$key] = $data[$index];
} else {
unset($result[$key]);
}
}
var_export(array_values($result));
Output:
array (
0 =>
array (
'venue1' => 3,
'venue2' => 4,
),
1 =>
array (
'venue1' => 5,
'venue2' => 6,
),
)
I have the following multidimensional array:
array(
array(
[id] => 65,
[user_id] => 1,
[total] => 1
),
array(
[id] => 66,
[user_id] => 3,
[total] => 2
),
array(
[id] => 67,
[user_id] => 5,
[total] => 4
),
)
How do I get the array with the highest value for total and I still get the full key Value for the array like this:
array(
[id] => 67,
[user_id] => 5,
[total] => 4
)
Try this:
$total = array();
foreach ($data as $key => $row) {
$total[$key] = $row['total'];
}
// this sorts your $data array by `total` in descending order
// so the max for `total` is the first element
array_multisort($total, SORT_DESC, $data);
And now, use $data[0];
Order the arrays on id using usort():
function cmp($a, $b)
{
return strcmp($b["id"], $a["id"]);
}
usort($arr, 'cmp'); // $arr is your array
Then the first array has your desired values.
See the documentation on usort for more information: http://php.net/manual/en/function.usort.php
$array = [
['id' => 1, 'total' => 1],
['id' => 2, 'total' => 4],
['id' => 3, 'total' => 5],
];
function cmp($a, $b) {
return ($a['total'] < $b['total']) ? 1 : -1;
}
usort($array, 'cmp');
print_r($array[0]); // output ['id' => 3, 'total' => 5]
You can use array_column() with array_search():
$totals = array_column( $array, 'total' );
$result = $array[ array_search( max( $totals ), $totals ) ];
array_column() return an array with 'total' values. Use it to retrieve the key of main array with max total value.
But... what about following array?
$array = array(
array(
'id' => 65,
'user_id' => 1,
'total' => 4
),
array(
'id' => 66,
'user_id' => 3,
'total' => 2
),
array(
'id' => 67,
'user_id' => 5,
'total' => 4
),
array(
'id' => 68,
'user_id' => 6,
'total' => 2
)
);
To filter all max values, you can use this:
$max = max( array_column( $array, 'total' ) );
$result = array_filter
(
$array,
function( $row ) use ( $max )
{
return $row['total'] == $max;
}
);
print_r( $result );
Output:
Array
(
[0] => Array
(
[id] => 65
[user_id] => 1
[total] => 4
)
[2] => Array
(
[id] => 67
[user_id] => 5
[total] => 4
)
)
Put in $max variable max value of 'total' column, then use it to filter original array and retrieve all rows having it as total.
Read more about array_column()
Read more about array_filter()
You can install xdebug for var_dump
and look you array by
var_dump($array);
after you can get needing array by key
$array[3]; //example for question context
or get by foreach for analyses you array
$arrayResult = array();
foreach($array as $_arr) {
if($_arr['user_id'] == 5) {
$arrayResult = $_arr;
}
}
var_dump($arrayResult);
this is example for your question context too
This question already has answers here:
Find intersecting rows between two 2d arrays comparing differently keyed columns
(3 answers)
Closed 4 months ago.
I have two arrays
Array
(
[0] => Array
(
[id] => 1
[affiliate_id] => 190
)
[1] => Array
(
[id] => 2
[affiliate_id] => 946
)
)
Array
(
[0] => Array
(
[id] => 1
[user_id] => 190
)
[1] => Array
(
[id] => 2
[user_id] => 246
)
[2] => Array
(
[id] => 3
[user_id] => 249
)
[3] => Array
(
[id] => 3
[user_id] => 250
)
)
Now i want to get an array which has value like this
if affiliate_id of first array exists in second array as user_id then i will get its value in third array like
Array
(
[0] => Array
(
[affiliate_id] => 190
)
)
i just want affiliate_id which is exists in second array as user_id
$a = Array(
Array('id' => 1, 'affiliate_id' => 190),
Array('id' => 2, 'affiliate_id' => 946)
);
$b = Array(
Array('id' => 1, 'user_id' => 190),
Array('id' => 2, 'user_id' => 246),
Array('id' => 3, 'user_id' => 249),
Array('id' => 3, 'user_id' => 250)
);
$c = array_map(function ($arr) { return $arr['affiliate_id']; }, $a);
$d = array_map(function ($arr) { return $arr['user_id']; }, $b);
$e = array_intersect($c, $d);
print_r($e);
try in_array() with loop
$a = firstarray;
$b = second array;
$i =0;
foreach($b as $k=>$v) {
if(!empty($a[$i])) {
if(in_array($v['user_id'], $a[$i])) {
$c[]['affiliate_id'] = $v['user_id'];
}
}
$i++;
}
print_r($c);
output :-
Array
(
[0] => Array
(
[affiliate_id] => 190
)
)
Use the following code:
<?php
$arr1 = array(array('id' => 1, 'affiliate_id' => 190),
array('id' => 2, 'affiliate_id' => 946));
$arr2 = array(array('id' => 1, 'user_id' => 190),
array('id' => 2, 'user_id' => 246),
array('id' => 3, 'user_id' => 249),
array('id' => 4, 'user_id' => 250));
$count = 0;
foreach ($arr1 as $k1 => $v1) {
if (in_array($v1['affiliate_id'], $arr2[$count]))
{
$arr3[]['affiliate_id'] = $v1['affiliate_id'];
}
$count++;
}
echo '<pre>'; print_r($arr3);
Output
Array
(
[0] => Array
(
[affiliate_id] => 190
)
)
I have 2 arrays:
Array ( [0] => Array ( [intTrackId] => 41 [intAverageRating] => 10 [bolNewRelease] => 0 [dtDateAdded] => 2013-03-08 17:32:26 ) [1] => Array ( [intTrackId] => 1 [intAverageRating] => 7 [bolNewRelease] => 0 [dtDateAdded] => 2013-03-08 18:54:35 ))
Array ( [0] => Array ( [intTrackId] => 41 [intAverageRating] => 5.5000 [bolNewRelease] => 1 [dtDateAdded] => 2014-03-25T09:39:28Q ) [1] => Array ( [intTrackId] => 361 [intAverageRating] => 8.0000 [bolNewRelease] => 1 [dtDateAdded] => 2014-03-25T09:39:28Q ))
I want to remove the items in the second which have a matching track ID in the first. So in this example, I would get:
Array ( [0] => Array ( [intTrackId] => 361 [intAverageRating] => 8.0000 [bolNewRelease] => 1 [dtDateAdded] => 2014-03-25T09:39:28Q ))
Is this possible with array_filter or is this a little complex for that?
Just use array_udiff() - it's intended to do this:
$one = Array (
0 => Array ('intTrackId' => 41, 'intAverageRating' => 10, 'bolNewRelease' => 0, 'dtDateAdded' => '2013-03-08 17:32:26' ),
1 => Array ('intTrackId' => 1, 'intAverageRating' => 7, 'bolNewRelease' => 0, 'dtDateAdded' => '2013-03-08 18:54:35' )
);
$two = Array (
0 => Array ('intTrackId' => 41, 'intAverageRating' => 5.5000, 'bolNewRelease' => 1, 'dtDateAdded' => '2014-03-25T09:39:28Q' ),
1 => Array ('intTrackId' => 361, 'intAverageRating' => 8.0000, 'bolNewRelease' => 1, 'dtDateAdded' => '2014-03-25T09:39:28Q' )
);
$result = array_udiff($two, $one, function($x, $y)
{
return $x['intTrackId']-$y['intTrackId'];
});
Yes it can be done with array_filter:
$array1 = array(...);
$array2 = array(...);
$newArray = array_filter($array2, function($item) use ($array1){
foreach($array1 as $elem){
if($item['intTrackId'] == $elem['intTrackId']){
return false;
}
}
return true;
});
I would first create a loop and store all track IDs from the first array in a separate array.
Then I'd loop over the second array and delete those keys that exist in the track ID array.
$track_ids = array();
foreach($array1 as $index => $items) {
$track_ids[$items['intTrackId']] = $index;
}
foreach($array2 as $items) {
if (isset($track_ids[$items['intTrackId']])) {
unset($array2[$track_ids[$items['intTrackId']]]);
}
}
I have two arrays, I want to merge these two arrays into single array. Please view the detail below:
First Array:
Array
(
[0] => Array
(
[a] => 1
[b] => 2
[c] => 3
)
[1] => Array
(
[a] => 3
[b] => 2
[c] => 1
)
)
Second Array:
Array
(
[0] => Array
(
[d] => 4
[e] => 5
[f] => 6
)
[1] => Array
(
[d] => 6
[e] => 5
[f] => 4
)
)
I want this result. Does somebody know how to do this?
Array
(
[0] => Array
(
[0] => 1
[1] => 2
[2] => 3
)
[1] => Array
(
[0] => 3
[1] => 2
[2] => 1
)
[2] => Array
(
[0] => 4
[1] => 5
[2] => 6
)
[3] => Array
(
[0] => 6
[1] => 5
[2] => 4
)
)
Hope you have understand the question.
Thank you in advance.
Try array_merge:
$result = array_merge($array1, $array2);
FIXED (again)
function array_merge_to_indexed () {
$result = array();
foreach (func_get_args() as $arg) {
foreach ($arg as $innerArr) {
$result[] = array_values($innerArr);
}
}
return $result;
}
Accepts an unlimited number of input arrays, merges all sub arrays into one container as indexed arrays, and returns the result.
EDIT 03/2014: Improved readability and efficiency
more simple and modern way is:
$merged = $array1 + ['apple' => 10, 'orange' => 20] + ['cherry' => 12, 'grape' => 32];
new array syntax from php 5.4
If you want to return the exact result you specify in your question then something like this will work
function array_merge_no_keys() {
$result = array();
$arrays = func_get_args();
foreach( $arrays as $array ) {
if( is_array( $array ) ) {
foreach( $array as $subArray ) {
$result[] = array_values( $subArray );
}
}
}
return $result;
}
As a purely native function solution, merge the arrays, then reindex each subarray.
Code: (Demo)
$a = [
['a' => 1, 'b' => 2, 'c' => 3],
['a' => 3, 'b' => 2, 'c' => 1],
];
$b = [
['d' => 4, 'e' => 5, 'f' => 6],
['d' => 6, 'e' => 5, 'f' => 4],
];
var_export(
array_map('array_values' array_merge($a, $b))
);
Output:
array (
0 =>
array (
0 => 1,
1 => 2,
2 => 3,
),
1 =>
array (
0 => 3,
1 => 2,
2 => 1,
),
2 =>
array (
0 => 4,
1 => 5,
2 => 6,
),
3 =>
array (
0 => 6,
1 => 5,
2 => 4,
),
)