I'm writing a program that swaps largest and smallest number in multidimensional array. Largest number should be on the place where is the smallest, and smallest where is the largest, and the idea is to use pure logic, without any php function that could help me out.
Please check my code and help me about this problem.
For instance:
$array = [
[45, 456, 321, 344, 567],
[100, 434, 173, 400, 789],
[191, 211, 457, 809, 900],
[431, 323, 432, 805, 906],
[708, 232, 897, 101, 696]
];
New order should be:
$array = [
[906, 456, 321, 344, 567],
[100, 434, 173, 400, 789],
[191, 211, 457, 809, 900],
[431, 323, 432, 805, 45],
[708, 232, 897, 101, 696]
]
I've tried with adding and changing code with this piece of code, but it doesn't give me right results...
$min_index = $max_index = 0;
foreach($array as $k => $v){
if($v < $array[$min_index]){
$min_index = $k;
}
if($v > $array[$max_index]){
$max_index = $k;
}
}
$min = $array[$min_index];
$array[$min_index] = $array[$max_index];
$array[$max_index] = $min;
$array = [
[45, 456, 321, 344, 567],
[100, 434, 173, 400, 789],
[191, 211, 457, 809, 900],
[431, 323, 432, 805, 906],
[708, 232, 897, 101, 696]
];
$intRows = 4;
$intCols = 4;
$intMaxRow = $intMinRow = $intMaxCol = $intMinCol = 0;
$minIndex = $maxIndex = 1;
for($row = 0; $row < $intRows; $row++)
{
for($col = 0; $col < $intCols; $col++)
{
if($array[$row][$col] > $maxIndex)
{
$maxIndex = $array[$row][$col];
$intMaxRow = $row;
$intMaxCol = $col;
}
if($array[$row][$col] < $minIndex)
{
$minIndex = $array[$row][$col];
$intMinRow = $row;
$intMinCol = $col;
}
}
}
$arrNxm[$intMinRow][$intMinCol] = $minIndex;
$arrNxm[$intMaxRow][$intMaxCol] = $maxIndex;
echo "<pre>";
var_dump($arrNxm);
echo "</pre>";
You've got some logical issues in your code which is causing it to not work. You are going along the right lines though.
Issue 1
You have set the number of rows and columns incorrectly. There are not 4, there are 5 of each:
$intRows = 5;
$intCols = 5;
Issue 2
The next issue is with:
$minIndex = $maxIndex = 1;
If $minIndex is 1, then nothing in your array can be lower than it, so it's never going to be updated from 1. This should be something like:
$minIndex = 100000; // This is an arbitrary choice to fix the issue
$maxIndex = 1;
Issue 3
Next, you use $arrNxm in your code. There is no $arrNxm, it should be $array.
Issue 4
Finally, this is wrong because you are putting the minimum value back into the minimum position in the array:
$arrNxm[$intMinRow][$intMinCol] = $minIndex;
$arrNxm[$intMaxRow][$intMaxCol] = $maxIndex;
You just need to swap $minIndex and $maxIndex around:
$array[$intMinRow][$intMinCol] = $maxIndex;
$array[$intMaxRow][$intMaxCol] = $minIndex;
Full code
The fully working code is:
$array = [
[45, 456, 321, 344, 567],
[100, 434, 173, 400, 789],
[191, 211, 457, 809, 900],
[431, 323, 432, 805, 906],
[708, 232, 897, 101, 696]
];
$intRows = 5;
$intCols = 5;
$intMaxRow = $intMinRow = $intMaxCol = $intMinCol = 0;
$minIndex = 100000;
$maxIndex = 1;
for($row = 0; $row < $intRows; $row++)
{
for($col = 0; $col < $intCols; $col++)
{
if($array[$row][$col] > $maxIndex)
{
$maxIndex = $array[$row][$col];
$intMaxRow = $row;
$intMaxCol = $col;
}
if($array[$row][$col] < $minIndex)
{
$minIndex = $array[$row][$col];
$intMinRow = $row;
$intMinCol = $col;
}
}
}
$array[$intMinRow][$intMinCol] = $maxIndex;
$array[$intMaxRow][$intMaxCol] = $minIndex;
echo "<pre>";
var_dump($array);
echo "</pre>";
This outputs:
array(5) {
[0]=>
array(5) {
[0]=>
int(906)
[1]=>
int(456)
[2]=>
int(321)
[3]=>
int(344)
[4]=>
int(567)
}
[1]=>
array(5) {
[0]=>
int(100)
[1]=>
int(434)
[2]=>
int(173)
[3]=>
int(400)
[4]=>
int(789)
}
[2]=>
array(5) {
[0]=>
int(191)
[1]=>
int(211)
[2]=>
int(457)
[3]=>
int(809)
[4]=>
int(900)
}
[3]=>
array(5) {
[0]=>
int(431)
[1]=>
int(323)
[2]=>
int(432)
[3]=>
int(805)
[4]=>
int(45)
}
[4]=>
array(5) {
[0]=>
int(708)
[1]=>
int(232)
[2]=>
int(897)
[3]=>
int(101)
[4]=>
int(696)
}
}
Whereby 45 and 906 are swapped in position as you wanted.
Related
I need to merge multiple arrays into one where a specific key & its value are same. Here is the Sample_Array1
array(n) {
[0]=> array {
["a"]=> "m1"
["b"]=> "x2"
}
[1]=> array {
["a"]=> "n1"
["b"]=> "y2"
} ....
Sample_Array2 with one common key & other different ones.
array(n) {
[0]=> array {
["b"]=> "x2"
["c"]=> "p1"
}
[1]=> array {
["b"]=> "x2"
["d"]=> "q1"
}
[2]=> array {
["b"]=> "y2"
["e"]=> "r1"
} ....
Need to merge / append Sample_Array2 to Sample_Array1 where key-"b" & its value are same. The expected output:
array(n) {
[0]=>
array(2) {
["a"]=> "m1"
["b"]=> "x2"
["c"]=> "p1"
["d"]=> "q1"
}
[1]=>
array(2) {
["a"]=> "n1"
["b"]=> "y2"
["e"]=> "r1"
} ....
I have tried so many similar questions but couldn't find the exact result.
PHP merge arrays with a condition The answer given on this link is not solving the purpose, its making different array for each new key, while I need to append the new keys in one array.
This should work, assuming you have the "b" index in all sub arrays.
$array1 = array();
$array1[] = array("a" => "m1", "b" => "x2", "c" => null);
$array1[] = array("a" => "n1", "b" => "y2");
$array2 = array();
$array2[] = array("b" => "x2", "c" => "p1");
$array2[] = array("a" => null, "b" => "x2", "d" => "q1");
$array2[] = array("b" => "y2", "e" => "r1");
function merge_on_key($array1, $array2, $key) {
$result_array = array();
foreach($array1 as $key1 => $sub_array1) {
$merged_array = array();
$sub_array1 = array_filter($sub_array1);
foreach($array2 as $key2 => $sub_array2) {
$sub_array2 = array_filter($sub_array2);
if($sub_array1[$key] == $sub_array2[$key]) {
$merged_array = array_merge($sub_array1, $sub_array2, $merged_array);
unset($array2[$key2]);
}
}
if (!empty($merged_array)) {
$result_array[] = $merged_array;
}
}
return array_merge($result_array, $array2);
}
$final_array = merge_on_key($array1, $array2, "b");
print_r($final_array);
In case you have to match the "b" index within the $array1 itself too, then simply use it twice:
$array1 = merge_on_key($array1, $array1, "b");
$final_array = merge_on_key($array1, $array2, "b");
i really have no idea what you want to achieve here - but based on your description the following code works
$arrA = [
0 =>
[
'a' => 'm1',
'b' => 'x2'
],
1 =>
[
'a' => 'n1',
'b' => 'y2'
]
];
$arrB = [
0 =>
[
'b' => 'x2',
'c' => 'p1',
],
1 =>
[
'b' => 'x2',
'd' => 'q1',
],
2 =>
[
'b' => 'y2',
'e' => 'r1',
],
];
foreach($arrB AS $arrData)
{
foreach($arrData AS $key => $val)
{
if ((isset($arrData['a']) && $arrData['a'] == $arrA[0]['a']) || (isset($arrData['b']) && $arrData['b'] == $arrA[0]['b']))
{
$arrA[0][$key] = $val;
}
elseif ((isset($arrData['b']) && $arrData['b'] == $arrA[1]['a']) || (isset($arrData['b']) && $arrData['b'] == $arrA[1]['b']))
{
$arrA[1][$key] = $val;
}
}
}
print_r($arrA);
Created the arrays similar to yours. $new_array is the resultant array that you are looking for.
$a=array();
$a[0]=array('a'=>'m1', 'b'=>'x2');
$a[1]=array('a'=>'n1', 'b'=>'y2');
$b=array();
$b[0]=array('b'=>'x2', 'c'=>'p1');
$b[1]=array('b'=>'x2', 'd'=>'q1');
$b[2]=array('b'=>'y2', 'e'=>'r1');
foreach($a as $row){
//echo '<pre>'; print_r($row);
foreach($b as $c=>$row1){
//echo '<pre>'; print_r($row1);echo $c;die;
if($row['b']==$row1['b']){
$new_array[]=array_merge($row, $row1);
}
}
}echo '<pre>'; print_r($new_array);
// Gather all values of b from both arrays
$all_b = array_unique(array_merge(array_column($arr1, 'b'), array_column($arr2, 'b')));
$res = [];
// For each b value
foreach($all_b as $b) {
$temp = [];
// Scan the arrays for items with the same b value
foreach($arr1 as $a1) {
if ($a1['b'] == $b) $temp = array_merge($temp, $a1);
}
foreach($arr2 as $a2) {
if ($a2['b'] == $b) $temp = array_merge($temp, $a2);
}
// Save them to new array
$res[] = $temp;
}
print_r($res);
demo on eval
array(10) { [0]=> int(5)
[1]=> int(8)
[2]=> int(2)
[3]=> int(0)
[4]=> int(1)
[5]=> int(9)
[6]=> int(1)
[7]=> int(0)
[8]=> int(5)
[9]=> int(4)
}
Ok, so I have an array as above. What I would like to do is get the top x items, change them into 1 and the rest into 0 without messing with the keys so that I can implode it back in the correct order. So if I want top 5, the result should be something like:
array(10) { [0]=> int(1)
[1]=> int(1)
[2]=> int(0)
[3]=> int(0)
[4]=> int(0)
[5]=> int(1)
[6]=> int(0)
[7]=> int(0)
[8]=> int(1)
[9]=> int(1)
}
I tried using sort, but I think it messes up the keys.
Any help would be appreciated. Thanks.
Uhm, I don't know If I understand question, but maybe:
for ($i = 0; $i < $topX; $i++)
$arr[$i] = (int)1;
for ($i = $topX+1;$i < count($arr); $i++)
$arr[$i] = (int)0;
Or add IF:
for ($i = 0; $i < count($arr); $i++)
$arr[$i] = ($arr[$i] < $maxVal) ? (int)1 : (int)0;
Well, I guess this is what you are looking for. I believe that the code is self-explain because I have comment all the important concept in the code.
<?php
function top(&$arr, $top, $start = 0)
{
if (count($arr) > $start) {
// count the number of element that larger
// than the element at start position
$count = 0;
for($i = $start + 1; $i < count($arr); $i++) {
if ($arr[$start] < $arr[$i]) $count++;
}
// if there are more than [$top] number of element
// that is larger than this element
// it cannot be in the [$top] largest number
if ($count >= $top) {
$arr[$start] = 0;
} else {
$arr[$start] = 1;
$top -= 1;
}
// continue to next element
top($arr, $top, $start + 1);
}
}
$arr = array(5, 8, 2, 0, 1, 9, 1, 0, 5, 4);
top($arr, 5);
var_dump($arr);
?>
asort() sort an array and maintain index association.
PHP has some pretty neat array-functions you can work with. Here's one approach:
<?php
function change_top_items($array, $top_x) {
// first, sort the values and preserve the keys
uasort($array, function($a, $b) {
if ($a == $b) return 0;
return ($a < $b) ? -1 : 1;
});
// put the top x values in an array
$compare = array_slice($array, -$top_x);
// now walk through the original array
$modified = array_map(function($value) use ($compare) {
// if the current value is in the top x array
// set it to 1, else set it to 0
return in_array($value, $compare) ? 1 : 0;
}, $array);
// now sort the modified array by keys again and return it
ksort($modified);
return $modified;
}
$a = [5, 8, 2, 0, 1, 9, 1, 0, 5, 4];
print_r(change_top_items($a, 5));
And that's pretty much it.
Output:
Array
(
[0] => 1
[1] => 1
[2] => 0
[3] => 0
[4] => 0
[5] => 1
[6] => 0
[7] => 0
[8] => 1
[9] => 1
)
Here's a working exapmple: http://3v4l.org/HI2EH - As you can also see there, I've used a syntax which is only valid for PHP 5.4+. This concerns the short array notation and the use of closures. But this code can easily be converted into a syntax of the previous PHP versions.
I am trying to combine keys when they have similar values, and expect the result as a string. Actually I had no idea how to achieve this, although I run a few tests.
$array = array(
'a' => 65,
'b' => 31,
'c' => 100,
'd' => 31,
'e' => 31,
'f' => 31,
'h' => 23,
'i' => 23,
'j' => 23,
'k' => 23,
'l' => 48,
'm' => 48,
);
$results = array();
foreach ($array as $k => $v) {
// This is my attempt among others to no luck.
// Can not use array_key_exists because values are unpredictable.
$similars[$v] = $k;
$results[$v] = implode(", ", array_unique($similars)) . ' : ' . $v;
}
var_dump(implode("\n ", $results));
You can view the output:
http://codepad.org/ECekF3dq
I am almost there, but obviously wrong :(
Not expected:
string(72) "a : 65
a, f, c : 31
a, b, c : 100
a, f, c, k : 23
a, f, c, k, m : 48"
Expected:
a : 65
b, d, e, f : 31
c : 100
h, i, j, k : 23
l, m : 48
Those with the same values should collapse as one line.
Thanks for any hint.
You want to make $similars into an array of arrays. That way you can keep all the keys with that value.
$results = array();
$similars = array();
foreach ($array as $k => $v) {
if(!isset($similars[$v])){
$similars[$v] = array($k);
}
else{
$similars[$v][] = $k;
}
$results[$v] = implode(", ", $similars[$v]) . ' : ' . $v;
}
var_dump(implode("\n ", $results));
There might be a more elegant way of doing this, but I'd probably use two simple foreach loops:
function parseArray($data)
{
$tmp = array();
foreach ($data as $key => $item) {
// Check if we already created this key
if (isset($tmp[$item])) {
// Append if so
$tmp[$item] .= ', '.$key;
} else {
// Init if not
$tmp[$item] = $key;
}
}
// Now we stringify the tmp array.
$result = '';
foreach ($tmp as $key => $value) {
$result .= "$key : $value\n";
}
return $result;
}
$tmp = array();
foreach ($array as $k => $v) $tmp[$v][] = $k;
foreach ($tmp as $k => $v) echo implode(', ', $v) . ' : ' . $k . "\n<br />";
I think reversing the keys and values could be beneficial. Turn the integers into keys, and the chars into array values. This would enable you to maintain the desired one-to-many relationship:
$array = array(
'a' => 65,
'b' => 31,
'c' => 100,
'd' => 31,
'e' => 31,
'f' => 31,
'h' => 23,
'i' => 23,
'j' => 23,
'k' => 23,
'l' => 48,
'm' => 48,
);
$results = array();
foreach ($array as $k => $v) {
$results[$v][]=$k;
}
foreach ($results as $k=>$v) {
echo implode(',',$v) . " : " . $k . "\r\n";
}
the multidimensional array $results equals:
array(5) {
[65]=>
array(1) {
[0]=>
string(1) "a"
}
[31]=>
array(4) {
[0]=>
string(1) "b"
[1]=>
string(1) "d"
[2]=>
string(1) "e"
[3]=>
string(1) "f"
}
[100]=>
array(1) {
[0]=>
string(1) "c"
}
[23]=>
array(4) {
[0]=>
string(1) "h"
[1]=>
string(1) "i"
[2]=>
string(1) "j"
[3]=>
string(1) "k"
}
[48]=>
array(2) {
[0]=>
string(1) "l"
[1]=>
string(1) "m"
}
}
Final output:
a : 65
b,d,e,f : 31
c : 100
h,i,j,k : 23
l,m : 48
Try this
$array = array('a' => 65,'b' => 31,'c' => 100,'d' => 31,'e' => 31,'f' => 31,'h' => 23,
'i' => 23,'j' => 23,'k' => 23,'l' => 48,'m' => 48);
$similars = array();
foreach ($array as $k => $v) {
// This is my attempt among others to no luck.
// Can not use array_key_exists because values are unpredictable.
$key = array_search($v, $similars);
if (isset($similars[$key])) {
unset($similars[$key]);
$similars[$key.','.$k] = $v;
}
else
$similars[$k] = $v;
}
print_r($similars);
//display as expected
foreach($similars as $k => $v)
echo "</br>".$k.':'.$v;
I have issues sorting an multidimensional array.
The array looks like:
$array = array(
array("token" => array(100, 240, 348, 23, 17),
array("token" => array(293, 28, 283, 2, 28),
array("token" => array(842, 23, 72, 98, 114)
);
Now I want to sort them by "column". That means, the first column of numbers (100, 293, 842) must be sorted, then the second column (but keeping the first column as it is! It may happen that the columns have the same number with multiple rows) and so on.
Actually I tried this to do with usort(), but this will work only when sorting the first column:
function do_sort($a, $b) {
$tok_a = $a["token"];
$tok_b = $b["token"];
if ($tok_a[0] <= $tok_b[0])
return false;
else
return true;
}
usort($array, "do_sort");
How can I do this? Thanks
Here's possible solution:
get rid of 'token', i.e., make 2D array
swap columns and rows (transpose array)
sort each column
swap back columns and rows (get initial structure)
put 'token' back
Code:
function array_transpose(array $array) {
$result = array();
foreach ( $array as $rowNum => $row ) {
foreach ( $row as $colNum => $value ) {
$result[$colNum][$rowNum] = $value;
}
}
return $result;
}
$array = array(
array("token" => array(100, 240, 348, 23, 17)),
array("token" => array(293, 28, 283, 2, 28)),
array("token" => array(842, 23, 72, 98, 114)),
);
// get rid of 'token'
foreach ( $array as &$item ) {
$item = $item['token'];
}
unset($item);
// swap columns and rows
$array = array_transpose($array);
// sort columns
foreach ( $array as &$item ) {
sort($item);
}
unset($item);
// swap back columns and rows
$array = array_transpose($array);
// put 'token' back
foreach ( $array as &$item ) {
$item = array('token' => $item);
}
unset($item);
// display results
foreach ( $array as $row ) {
foreach ( $row['token'] as $value ) {
printf('%-7d', $value);
}
echo "\n";
}
Output:
100 23 72 2 17
293 28 283 23 28
842 240 348 98 114
I think this will do what you are after. I've made some assumptions here (such as $array is really an array, has at least one sub-array, all sub-arrays have token as the key, and all sub-arrays have the same number of elements).
<?php
$array = array(
array("token" => array(100, 240, 348, 23, 17)),
array("token" => array(293, 28, 283, 2, 28)),
array("token" => array(842, 23, 72, 98, 114)),
);
$count_outer = count($array);
$count_inner = count($array[0]['token']);
for ($i=0; $i < $count_inner; $i++) {
$temp_arr = array();
for ($j=0; $j < $count_outer; $j++) {
$temp_arr[] = $array[$j]['token'][$i];
}
sort($temp_arr);
for ($j=0; $j < $count_outer; $j++) {
$array[$j]['token'][$i] = $temp_arr[$j];
}
}
foreach ($array as $value) {
var_dump($value);
echo '<br>';
}
Output:
array(1) { ["token"]=> array(5) {
[0]=> int(100) [1]=> int(23) [2]=>
int(72) [3]=> int(2) [4]=> int(17) } }
array(1) { ["token"]=> array(5) {
[0]=> int(293) [1]=> int(28) [2]=>
int(283) [3]=> int(23) [4]=> int(28) }
} array(1) { ["token"]=> array(5) {
[0]=> int(842) [1]=> int(240) [2]=>
int(348) [3]=> int(98) [4]=> int(114)
} }
Can't you just
foreach ($array as &$item) {
sort($item['token']);
}
Or have I misunderstood the question?
I have an array in the following format:
array(
0 => array(1, 5),
1 => array(4, 8),
2 => array(19, 24),
3 => array(6, 9),
4 => array(11, 17),
);
Where each item is a X-to-Y range. What I would like to merge the overlapping ranges in the array, to get something more like this:
array(
0 => array(1, 9), // 1-5, 4-8 and 6-9 are overlapping, so they are merged
1 => array(11, 17),
2 => array(19, 24),
);
What would be the best way to accomplish this?
Untested, but the idea here is to sort the data first by the first element, then merge subsequent elements with the previous one as long as possible.
usort($data, function($a, $b)
{
return $a[0] - $b[0];
});
$n = 0; $len = count($data);
for ($i = 1; $i < $len; ++$i)
{
if ($data[$i][0] > $data[$n][1] + 1)
$n = $i;
else
{
if ($data[$n][1] < $data[$i][1])
$data[$n][1] = $data[$i][1];
unset($data[$i]);
}
}
$data = array_values($data);
$input = array( 0 => array(1, 5),
1 => array(4, 8),
2 => array(19, 24),
3 => array(6, 9),
4 => array(11, 17),
);
$tmpArray = array();
foreach($input as $rangeSet) {
$tmpArray = array_unique(array_merge($tmpArray,range($rangeSet[0],$rangeSet[1])));
}
sort($tmpArray);
$oldElement = array_shift($tmpArray);
$newArray = array(array($oldElement));
$ni = 0;
foreach($tmpArray as $newElement) {
if ($newElement > $oldElement+1) {
$newArray[$ni++][] = $oldElement;
$newArray[$ni][] = $newElement;
}
$oldElement = $newElement;
}
$newArray[$ni++][] = $oldElement;
var_dump($newArray);
Alright, drafted this up, so it may have quirks. Tested it with the data seen below and seemed to work just fine. May not be the best way to do it, but it is one way and it does work. Questions let me know.
function combineRange($array) {
if (is_array($array)) {
// Sort the array for numerical order
sort($array);
// Set Defaults
$prev = array();
$prev_key = null;
foreach ($array as $key => $item) {
// First time around setup default data
if (empty($prev)) {
$prev = $item;
$prev_key = $key;
continue;
}
if ($item[0] >= $prev[0] && $item[0] <= $prev[1]) {
// Incase the last number was less than do not update
if ($array[$prev_key][1] < $item[1])
$array[$prev_key][1] = $item[1];
unset($array[$key]);
}else {
$prev_key = $key;
}
$prev = $item;
}
}
return $array;
}
$array = array(
5 => array(13, 16),
0 => array(1, 5),
1 => array(4, 8),
2 => array(19, 24),
3 => array(6, 9),
4 => array(11, 17),
6 => array(21, 30),
);
var_dump(combineRange($array));
Outputs:
array(3) {
[0]=>
array(2) {
[0]=>
int(1)
[1]=>
int(9)
}
[3]=>
array(2) {
[0]=>
int(11)
[1]=>
int(17)
}
[5]=>
array(2) {
[0]=>
int(19)
[1]=>
int(30)
}
}
Hope it works for ya!
EDIT
I see I was beaten out by an hour =\ Oh well! I am still posting as it is a different method, granted I would probably choose konforce's method instead.