I want to sort my array which contains names as keys and numbers as values, a function for each of sorting by key and by value.
I'm aware of asort() and ksort(), but I want to do this manually. Originally I tried bubble sort, but quickly realised it didn't work as the keys were strings, not numbers.
How would I go about doing this? So if I have the array:
$ar = array("A" => 10, "D" => 25, "G" => 12)
How would I sort the array by value and by key? I can't find a way of cycling through it and sorting the two different values.
This code may be use full.
$ar = array("A" => 10, "D" => 25, "G" => 12,'B'=>11);
function bubbleSortValues($array){ // sort by value
$new_array = array_values($array); // get array values
$length = count($new_array);
// perform buuble sort
for ($outer = 0; $outer < $length; $outer++) {
for ($inner = 0; $inner < $length; $inner++) {
if ($new_array[$outer] < $new_array[$inner]) {
$tmp = $new_array[$outer];
$new_array[$outer] = $new_array[$inner];
$new_array[$inner] = $tmp;
}
}
}
// loop the sorted array and generate original array with keys and values
foreach($new_array as $key=>$value){
$sorted_array[array_search($value, $array)] = $value;
}
return $sorted_array;
}
function bubbleSortKeys($array){ //sort by key
$new_array = array_keys($array); // get array keys
$length = count($new_array);
// perform buuble sort
for ($outer = 0; $outer < $length; $outer++) {
for ($inner = 0; $inner < $length; $inner++) {
if ($new_array[$outer] < $new_array[$inner]) {
$tmp = $new_array[$outer];
$new_array[$outer] = $new_array[$inner];
$new_array[$inner] = $tmp;
}
}
}
// loop the sorted array and generate original array with keys and values
foreach($new_array as $key=>$value){
$sorted_array[$value] = $array[$value];
}
return $sorted_array;
}
echo "<pre>";
$values = bubbleSortValues($ar);
print_r($values);
$keys = bubbleSortKeys($ar);
print_r($keys);
OUT PUT:
Array
(
[A] => 10
[B] => 11
[G] => 12
[D] => 25
)
Array
(
[A] => 10
[B] => 11
[D] => 25
[G] => 12
)
Use strcmp to compare strings.
Related
$tag=[25, 26];
$tagarray[]=[25,29,30,44,26];
I need a result of [29,30,44]. Here my main array is tagarray. and tested it with tag array. I need unmatched values from tagarray without any array function like array_diff().I want to compare both arrays and only provide the elements from tagarray which are not present in tag array.
$missings = [];
$matches = false;
for ( $i = 0; $i < count($tagarray); $i++ ) {
$matches = false;
for ($e = 0; $e < count($tag); $e++ ) {
if ( $tagarray[$i] == $tag[$e] ) $matches = true;
}
if(!$matches) array_push($missings,$tagarray[$i]);
}
dd($missings);
You need nested for loops to loop over each element of your array to filter, and for each of these elements, loop on the array containing the filters.
Since you do not want to use any of the array function, you need to use a boolean to check whether or not the index was to be filtered or not and make use of a 3rd array to store the filtered array.
Take a look:
$tag = [25, 26];
$tagarray = [25,29,30,44,26];
$filteredArray = [];
for($i = 0; $i < count($tagarray); ++$i){
$toRemove = false;
for($j = 0; $j < count($tag); ++$j){
if($tagarray[$i] == $tag[$j]){
$toRemove = true;
break;
}
}
if(!$toRemove){
$filteredArray[] = $tagarray[$i];
}
}
var_dump($filteredArray);
Output
array(3) {
[0]=>
int(29)
[1]=>
int(30)
[2]=>
int(44)
}
I would personally not choose this solution and go with Aksen's one, but since you do not want to use any array functions I assume that this is a school assignment and that you have no other choices ;)
If you don't want to use array_diff() then you can use in_array():
$res = [];
foreach($tagarray[0] as $val){
if (!in_array($val,$tag)) $res[] = $val;
}
print_r($res);
Output:
Array
(
[0] => 29
[1] => 30
[2] => 44
)
Demo
If $tagarray has more then 1 element:
$tag=[25, 26];
$tagarray[]=[25,29,30,44,26];
$tagarray[]=[25,22,11,44,26];
$res = [];
foreach($tagarray as $ind=>$tagar){
foreach($tagar as $val){
if (!in_array($val,$tag)) $res[$ind][] = $val;
}
}
Output:
Array
(
[0] => Array
(
[0] => 29
[1] => 30
[2] => 44
)
[1] => Array
(
[0] => 22
[1] => 11
[2] => 44
)
)
Demo
Third Without any inbuilt PHP array function:
$tagar_l = count($tagarray);
$tag_l = count($tag);
$tagar_0_l = count($tagarray[0]);
$res = [];
for($i = 0; $i<$tagar_l; $i++){
$res[] = $tagarray[$i];
for($j = 0; $j<$tagar_0_l; $j++){
for($k = 0; $k<$tag_l; $k++){
if ($tag[$k] === $tagarray[$i][$j]) unset($res[$i][$j]);
}
}
sort($res[$i]);
}
Demo
Via foreach loop:
$res = [];
foreach($tagarray as $ind=>$arr){
$res[] = $arr;
foreach($arr as $ind_a=>$val){
foreach($tag as $comp){
if ($comp === $val) unset($res[$ind][$ind_a]);
}
}
sort($res[$ind]);
}
Demo
I am trying to get an factorial value of each item in array by using this method but this outputs only one value
can any body help me finding where i am doing wrong?
function mathh($arr, $fn){
for($i = 1; $i < sizeof($arr); $i++){
$arr2 = [];
$arr2[$i] = $fn($arr[$i]);
}
return $arr2;
}
$userDefined = function($value){
$x = 1;
return $x = $value * $x;
};
$arr = [1,2,3,4,5];
$newArray = mathh($arr, $userDefined);
print_r($newArray);
You're going to need a little recursion so in order to do that you need to pass the lambda function into itself by reference:
function mathh($arr, $fn){
$arr2 = []; // moved the array formation out of the for loop so it doesn't get overwritten
for($i = 0; $i < sizeof($arr); $i++){ // starting $i at 0
$arr2[$i] = $fn($arr[$i]);
}
return $arr2;
}
$userDefined = function($value) use (&$userDefined){ // note the reference to the lambda function $userDefined
if(1 == $value) {
return 1;
} else {
return $value * $userDefined($value - 1); // here is the recursion which performs the factorial math
}
};
$arr = [1,2,3,4,5];
$newArray = mathh($arr, $userDefined);
print_r($newArray);
The output:
Array
(
[0] => 1
[1] => 2
[2] => 6
[3] => 24
[4] => 120
)
I wanted to expand on this some since you're essentially (in this case) creating an array map. This could be handy if you're doing additional calculations in your function mathh() but if all you want to do is use the lambda function to create a new array with a range you could do this (utilizing the same lambda we've already created):
$mapped_to_lambda = array_map($userDefined, range(1, 5));
print_r($mapped_to_lambda);
You will get the same output, because the range (1,5) of the mapped array is the same as your original array:
Array
(
[0] => 1
[1] => 2
[2] => 6
[3] => 24
[4] => 120
)
I have a simple array that looks like this:
Array (
[0] => Array (
[id] => 8692
[name] => d
)
[1] => Array (
[id] => 8691
[name] => c
)
[2] => Array (
[id] => 8690
[name] => b
)
[3] => Array (
[id] => 8689
[name] => a
)
[4] => Array (
[id] => 8500
[name] => d
)
[5] => Array (
[id] => 8499
[name] => c
)
[6] => Array (
[id] => 8498
[name] => b
)
[7] => Array (
[id] => 8497
[name] => a
)
)
This array is quite long so I only included the first 4 items to give you an idea.
My problem is that I need the array to be in a format of
a,b,c,d,a,b,c,d
At the moment the format is like:
d,c,b,a,d,c,b,a
By this I mean the ['name'] value which is either a,b,c or d.
So I every 4 items in the array need to be reversed.
I have tried to achieve this but fail every time ending up with lots of for & while loops.
You can do it using array_chunk, array_merge and array_reverse:
$finalArray = array();
$arrays = array_chunk($myArray, 4);
foreach ($arrays as $array) {
$finalArray = array_merge($finalArray, array_reverse($array));
}
All the answers here, while perfectly valid, are pretty much on the order of O(n^2). So I figured I'd give you an O(n / 2), time complexity, solution as an alternative just in case you care about performance. The solution also uses only O(n + n + k) space complexity (in place swap).
Since the requirement is to reverse order of values, I'm ignoring keys and basing the solution on the constraint that the array is always 0-indexed.
To solve this problem, we can generalize the solution as a simple array reverse, which requires a simple O(n/2) operation with in-place swap. We can achieve this simply with two counters, $i starting from the beginning of the array, and $j starting at the end of the array. Thus, we can swap the values at $arr[$i] with that at $arr[$j] and then increment $i and decrement $j, at each step.
function reverseArray(Array $arr) {
for($i = 0, $j = count($arr); $i < $j; $i++, $j--) {
$tmp = $arr[$j];
$arr[$j] = $arr[$i];
$arr[$i] = $tmp;
}
return $arr;
}
Now, to apply the more specific solution of only reverse every group of 4 elements in the array, we just break up the array in partitions of 4 values, and only reverse each of those partitions at a time. Which just expands on the example above of reverseArray() by altering the starting and ending positions of the $i and $j counter to only reverse within each partition.
Thus we arrive the O(n / 2) solution here by just adding another loop for the partition size, and keep the inner loop from the earlier example.
function reverseArrayPartition(Array $arr, $partitionSize = 4) {
$end = count($arr);
// reverse only one partition at a time
for($start = 0; $start < $end; $start += $partitionSize ) {
$from = $start;
$to = $start + $partitionSize - 1;
for($i = $from, $j = $to; $i < $j; $i++, $j--) {
// swap the transposing values
$tmp = $arr[$j];
$arr[$j] = $arr[$i];
$arr[$i] = $tmp;
}
}
return $arr;
}
$arr = [4,3,2,1,4,3,2,1];
var_dump(reverseArrayPartition($arr)); // expected [1,2,3,4,1,2,3,4]
This will work with any array size at any $partitionSize so it's efficient if you're trying to do this on very large arrays.
You can iterate the array with a for and increment with 4 each time and keep the current offset in other variable and use array_slice to get the current slice of array and reverse order using array_reverse
I am thinking of something like this:
$step = 4;
$offset = 0;
$new_arr = []; //Here we create the new array.
for($i=0; $i<count($arr); $i+=$step) {
$part_of_array = array_slice($arr, $offset, $step);
$part_reverse = array_reverse($part_of_array);
$new_arr = array_merge($new_arr, $part_reverse);
$offset += $step;
}
print_r($new_arr); //Here will be the array as you expected.
All the content in the for can be simplify to:
$new_arr = array_merge($new_arr, array_reverse(array_slice($arr, $offset, $step)));
$offset += $step;
Not harcoding every 4, reverse based on char code of name value
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
/**
*/
$in = [
['name'=>'d','id'=>1]
, ['name'=>'c','id'=>12]
, ['name'=>'b','id'=>13]
, ['name'=>'a','id'=>14]
, ['name'=>'d','id'=>15]
, ['name'=>'c','id'=>16]
, ['name'=>'b','id'=>17]
, ['name'=>'a','id'=>18]
];
$last = PHP_INT_MAX;
$toReverse = [];
$out = [];
foreach ($in as $value) {
$p = ord($value['name']);
if ( $p < $last ) {
//echo 'ToReverse',var_export($value,true),"\n";
$toReverse[] = $value;
}
else {
$out = array_merge($out,array_reverse($toReverse));
//echo 'Join',var_export($out,true),"\n";
$toReverse = [$value];
}
$last = $p;
}
$out = array_merge($out,array_reverse($toReverse));
print_r($out);
I have 2 arrays in PHP. One of them holds a list of dates, the other a list of numbers.
Array1
(
[0] => 2010-06-14
[1] => 2010-06-14
[2] => 2010-06-14
[3] => 2014-01-26
[4] => 2014-01-26
)
Array2
(
[0] => 120
[1] => 100
[2] => 60
[3] => 140
[4] => 30
)
The value [0] in Array2 belongs with the date [0] in Array1. What I am trying to do is add all of the values in Array2 together, based on the date. Any dates that match should have their values added together. So for example at the end I would like something like:
$date = 2010-06-14;
$value = 280;
$date = 2014-01-26;
$value = 170;
...and so on.
I've searched though the site but was unable to find exactly what I needed. Any help would be appreciated...
You can iterate $values, and get the corresponding date from $dates to use as the key in your result array.
foreach ($values as $key => $value) {
$result[$dates[$key]] = $value + ($result[$dates[$key]] ?? 0);
}
The output will be like this:
array (size=2)
'2010-06-14' => int 280
'2014-01-26' => int 170
$sum=0; // New Element
$Array3[][]=0; // New 2D array
$p=0; // Counter for 2D array
for($i=0;$i<5;$i++) // Single loop for traversing
{
$date=Array1[$i]; // Start for a date
while($date==Array1[$i]){ // For for Similar date
$sum=$sum+Array2[$i]; // Adding values of similar date
$i++; // Increment array
}
$Array3[$p]["date"]=$date; // Array3 date element
$Array3[$p]["sum"]=$sum; // Array4 date element
$i--; // Reducing a value which is incremented in while loop
}
Array3 is like
Array3
(
[0] => array( 'date' => " ",'sum' => " ")
[1] => array( 'date' => " ",'sum' => " ")
)
Are you trying to count all of the values in Array2 that have an entry in Array1 that matches some predefined target value?
If so, this for loop version should work:
private function forLoopVersion($array1, $array2, $target) {
$result = 0;
for ($i = 0; $i < count($array1); ++$i) {
if ($array1[$i] == $target) {
$result += $array2[$i];
}
}
return $result;
}
Also, this foreach loop version might work, but I do not know if the $key for $array1 can be used to index an element in $array2. You could try it:
private function foreachLoopVersion($array1, $array2, $target) {
$result = 0;
foreach ($array1 as $key => $value) {
if ($value == $target) {
$result += $array2[$key];
}
}
return $result;
}
$newArray = array();
for($i = 0; $i < count(Array1); $i++) {
$newArray[$Array1[$i]] = $Array2[$i];
}
echo $newArray[$date1] + $newArray[$date2];
Put the dates as keys to for easy math.
This question already has answers here:
Transpose and flatten two-dimensional indexed array where rows may not be of equal length
(4 answers)
Closed 10 months ago.
How can I merge two arrays when array 1 values will be in even places and array 2 will be in odd places?
Example:
$arr1=array(11, 34,30);
$arr2=array(12, 666);
$output=array(11, 12, 34, 666,30);
This will work correctly no matter the length of the two arrays, or their keys (it does not index into them):
$result = array();
while(!empty($arr1) || !empty($arr2)) {
if(!empty($arr1)) {
$result[] = array_shift($arr1);
}
if(!empty($arr2)) {
$result[] = array_shift($arr2);
}
}
Edit: My original answer had a bug; fixed that.
try this
$arr1=array(11,34,30,35);
$arr2=array(12,666,23);
$odd= array_combine(range(0,2*count($arr1)-1,2), $arr1);
$even = array_combine(range(1,2*count($arr2)-1,2), $arr2);
$output=$odd+$even;
ksort($output);
echo "<pre>";
print_r($output);
returns
Array
(
[0] => 11
[1] => 12
[2] => 34
[3] => 666
[4] => 30
[5] => 23
[6] => 35
)
Assuming $arr1 and $arr2 are simple enumerated arrays of equal size, or where $arr2 has only one element less that $arr1.
$arr1 = array(11, 34);
$arr2 = array(12, 666);
$output = array();
foreach($arr1 as $key => $value) {
$output[] = $value;
if (isset($arr2[$key])) {
$output[] = $arr2[$key];
}
}
Go through array with more items, use loop index to access both arrays and combine them into resulting one as required...
$longer = (count($arr1) > count($arr2) ? $arr1 : $arr2);
$result = array();
for ($i = 0; $i < count($longer); $i++) {
$result[] = $arr1[i];
if ($arr2[i]) {
$result[] = $arr2[i];
} else {
$result[] = 0; // no item in arr2 for given index
}
}