Sort an array based on another array in php? - php

according to this answer -> Sort an Array by keys based on another Array?, I use this function to get my another array sorted:
function sortArrayByArray($array,$orderArray) {
$ordered = array();
foreach($orderArray as $key) {
if(array_key_exists($key,$array)) {
$ordered[$key] = $array[$key];
unset($array[$key]);
}
}
return $ordered + $array;
}
at first, I have my code like this and it works fine
$array1 = array("a","b","c");
$array2 = array("2","5","1");
$array3 = array("2","5","1");
rsort($array3); //5,2,1
for($i=0;$i<3;$i++){
$customer1[$array2[$i]] = $array1[$i];
}
$properOrderedArray1 = sortArrayByArray($customer1, $array3);
print_r($properOrderedArray1);
but when I use some logic math like multiply, it gets any errors like it said there is data type float
//multiply
$a = 100000*100000;
$b = 200000*200000;
$c = 300000*300000;
$array1 = array("a","b","c");
$array2 = array($a,$b,$c);
$array3 = array($a,$b,$c);
rsort($array3); //5,2,1
for($i=0;$i<3;$i++){
$customer1[$array2[$i]] = $array1[$i];
}
$properOrderedArray1 = sortArrayByArray($customer1, $array3);
print_r($properOrderedArray1);
var_dump($array2);
THE ERROR: Warning: array_key_exists(): The first argument should be either a string or an integer
so any solution for this problem?
Thanks.

As stated, you will have to convert your floats to strings. I guess you can alter your function to something like this to make it work:
function sortArrayByArray($array,$orderArray) {
$ordered = array();
foreach($orderArray as &$key) {
if (!is_int($key))
$key = number_format($key,0,'.','');
if(array_key_exists($key,$array)) {
$ordered[$key] = $array[$key];
unset($array[$key]);
}
}
return $ordered + $array;
}
The problem about doing it this way is that you lose precision in your float value. In a 64-bit system all these values
$a = 9223372036854775808;
$b = 9223372036854775809;
$c = 9223372036854775810;
will be converted into the same float(9.2233720368548E+18), and converting it to a string will give string(19) "9223372036854775808". As long as your indexes that you use for sorting have significant numbers in the upper range of the number it can work, but it's not a safe way of sorting.

Basically what i written in the comment is true as i just checked in the manual: http://php.net/manual/en/language.types.integer.php
$large_number = 2147483647; //treated as int
$large_number = 2147483648; //treated as float since it is too large for an integer
So the solution to your problem is to limit the indices to the max value of integers.
OR to convert the floats to strings, but i would NOT recommend that, but sadly that seems to be the only way to achieve what you are trying to do.

Related

compare two arrays in PHP and get the difference in key

I have been reading through the manual to find a function that does what I want but I ended up doing it myself. I want to compare two arrays and calculate the difference between the keys. Or more practically analyse the difference in order of the values.
I have done this as follows, but I have a feeling this can be done better.
if anyone has an idea how to improve this please let me know becasue im eager to improve.
<?php
$goodarray = array(300,250,200,150,100);
$usersupliedarray = array(250,300,200,150,100); // first two spots are wrong
$score = count($goodarray);
foreach($usersupliedarray as $key => $value){
$arraykey = array_search($value, $goodarray);
$difference = abs($key-$arraykey);
$score = $score + $difference;
echo "$value $goodarray[$key] ($difference = $score) <hr />";
}
array_map with a void callback can come in handy here, for example,
$a = array(300,250,200,150,100);
$b = array(250,300,200,150,100);
$faults = 0;
foreach(array_map(null, $a, $b) as $x)
$faults += $x[0] != $x[1]; // x[0] is $a element, x[1] is $b
print $faults; // 2
UPD: if you want to compute distances between equal elements, and not just count differences, your original code looks just fine to me. One improvement which can be made is to get rid of inefficient array_search and to use an "inverted index" of the first array instead:
foreach($a as $pos => $val)
$inv[$val] = $pos;
or just
$inv = array_flip($a);
and then
foreach($b as $pos => $val)
$score += abs($pos - $inv[$val]);

php explode and force array keys to start from 1 and not 0

I have a string that will be exploded to get an array, and as we know, the output array key will start from 0 as the key to the first element, 1 for the 2nd and so on.
Now how to force that array to start from 1 and not 0?
It's very simple for a typed array as we can write it like this:
array('1'=>'value', 'another value', 'and another one');
BUT for an array that is created on the fly using explode, how to do it?
Thanks.
$exploded = explode('.', 'a.string.to.explode');
$exploded = array_combine(range(1, count($exploded)), $exploded);
var_dump($exploded);
Done!
Just use a separator to create a dummy element in the head of the array and get rid of it afterwards. It should be the most efficient way to do the job:
function explode_from_1($separator, $string) {
$x = explode($separator, $separator.$string);
unset($x[0]);
return $x;
}
a more generic approach:
function explode_from_x($separator, $string, $offset=1) {
$x = explode($separator, str_repeat($separator, $offset).$string);
return array_slice($x,$offset,null,true);
}
$somearray = explode(",",$somestring);
foreach($somearray as $key=>$value)
{
$otherarray[$key+1] = $value;
}
well its dirty but isn't that what php is for...
Nate almost had it, but needed a temporary variable:
$someArray = explode(",",$myString);
$tempArray = array();
foreach($someArray as $key=>$value) {
$tempArray[$key+1] = $value;
}
$someArray = $tempArray;
codepad example
$array = array('a', 'b', 'c', 'd');
$flip = array_flip($array);
foreach($flip as &$element) {
$element++;
}
$normal = array_flip($flip);
print_r($normal);
Try this, a rather funky solution :P
EDIT: Use this instead.
$array = array('a', 'b', 'b', 'd');
$new_array = array();
$keys = array_keys($array);
for($i=0; $i<count($array); $i++) {
$new_array[$i+1] = $array[$i];
}
print_r($new_array);
I agree with #ghoti that this task is probably an XY Problem. I can't imagine a valid/professional reason to start keys from 1 -- I've never needed this functionality in over 10 years of development. I'll offer a compact looping approach, but I'll probably never need it myself.
After instatiating a counter which is one less than the desired first key, you can use a body-less foreach() as a one-liner.
Code: (Demo)
$i = 0;
$result = [];
foreach (explode('.', 'a.string.to.explode') as $result[++$i]);
var_export($result);

Find number which is greater than or equal to N in an array

If I have a PHP array:
$array
With values:
45,41,40,39,37,31
And I have a variable:
$number = 38;
How can I return the value?:
39
Because that is the closest value to 38 (counting up) in the array?
Regards,
taylor
<?php
function closest($array, $number) {
sort($array);
foreach ($array as $a) {
if ($a >= $number) return $a;
}
return end($array); // or return NULL;
}
?>
Here is a high-level process to get the desired results and work for any array data:
Filter the array keeping on values greater than or equal to the target and then select the lowest remaining value. This is the "best" value (which may be "nothing" if all the values were less) -- this is O(n)
Alternatively, sort the data first and see below -- this is O(n lg n) (hopefully)
Now, assuming that the array is sorted ASCENDING, this approach would work:
Loop through the array and find the first element which is larger than or equal to the target -- this is O(n)
And if the array is DESCENDING (as in the post), do as above, but either:
Iterate backwards -- this is O(n)
Sort it ASCENDING first (see fardjad's answer) -- this is O(n lg n) (hopefully)
Iterate forwards but keep a look-behind value (to remember "next highest" if the exact was skipped) -- this is O(n)
Happy coding.
EDIT typo on array_search
Yo... Seems easy enough. Here's a function
<?php
$array = array(45,41,40,39,37,31);
function closest($array, $number){
#does the array already contain the number?
if($i = array_search( $number, $array)) return $i;
#add the number to the array
$array[] = $number;
#sort and refind the number
sort($array);
$i = array_search($number, $array);
#check if there is a number above it
if($i && isset($array[$i+1])) return $array[$i+1];
//alternatively you could return the number itself here, or below it depending on your requirements
return null;
}
to Run echo closest($array, 38);
Here's a smaller function that will also return the closest value. Helpful if you don't want to sort the array (to preserve keys).
function closest($array, $number) {
//does an exact match exist?
if ($i=array_search($number, $array)) return $i;
//find closest
foreach ($array as $match) {
$diff = abs($number-$match); //get absolute value of difference
if (!isset($closeness) || (isset($closeness) && $closeness>$diff)) {
$closeness = $diff;
$closest = $match;
}
}
return $closest;
}
Do a linear scan of each number and update two variables and you'll be done.
Python code (performance is O(N), I don't think it's possible to beat O(N)):
def closestNum(numArray, findNum):
diff = infinity # replace with actual infinity value
closestNum = infinity # can be set to any value
for num in numArray:
if((num - findNum) > 0 and (num - findNum) < diff):
diff = num - findNum
closestNum = num
return closestNum
Please add null checks as appropriate.
If you really want the value that's "closest" in distance, even if it's a lesser value, try this, which #Jason gets most of the credit for.
Imagine a scenario when you want the closest number to 38.9 in the following:
$array = array(37.5, 38.5, 39.5);
Most of the solutions here would give you 39.5, when 38.5 is much closer.
This solution would only take the next highest value if what you're looking is in the exact middle between two numbers in the array:
function nearest_value($value, $array) {
if (array_search($value, $array)) {
return $value;
} else {
$array[] = $value;
sort($array);
$key = array_search($value, $array);
if ($key == 0) { return $array[$key+1]; }
if ($key == sizeof($array)-1) { return $array[$key-1]; }
$dist_to_ceil = $array[$key+1]-$value;
$dist_to_floor = $value-$array[$key-1];
if ($dist_to_ceil <= $dist_to_floor) {
return $array[$key+1];
} else {
return $array[$key-1];
}
}
}
What it lacks in elegance, it makes up for in accuracy. Again, much thanks to #Jason.
Try this simple PHP function:
<?php
function nearest($number, $numbers) {
$output = FALSE;
$number = intval($number);
if (is_array($numbers) && count($numbers) >= 1) {
$NDat = array();
foreach ($numbers as $n)
$NDat[abs($number - $n)] = $n;
ksort($NDat);
$NDat = array_values($NDat);
$output = $NDat[0];
}
return $output;
}
echo nearest(90, array(0, 50, 89, 150, 200, 250));
?>
I made a shorter function for that:
function nearestNumber($num, $array) {
if(!in_array($num, $array)) $array[] = $num;
sort($array);
$idx = array_search($num, $array);
if(($array[$idx] -$array[$idx-1]) >= ($array[$idx+1] -$array[$idx])) return $array[$idx+1];
else return $array[$idx-1];
}
Works great in my case: $array = array(128,160,192,224,256,320); $num = 203 :)
It's taking the nearest number and if there's the same distance between two numbers (like 208 for my example), the next highest number is used.
+1 to Jason.
My implementation below, but not as brisk
$array = array(1,2,4,5,7,8,9);
function closest($array, $number) {
$array = array_flip($array);
if(array_key_exists($number, $array)) return $number;
$array[$number] = true;
sort($array);
$rendered = array_slice($array, $number, 2, true);
$rendered = array_keys($rendered);
if(array_key_exists(1, $rendered)) return $rendered[1];
return false;
}
print_r(closest($array, 3));
You could use array_reduce for this, which makes it more functional programming style:
function closest($needle, $haystack) {
return array_reduce($haystack, function($a, $b) use ($needle) {
return abs($needle-$a) < abs($needle-$b) ? $a : $b;
});
}
For the rest, this follows the same principle as the other O(n) solutions.
Here is my solution.
$array=array(10,56,78,17,30);
$num=65;
$diff=$num;
$min=$num;
foreach($array as $a){
if( abs($a-$num)< $diff ){
$diff=abs($a-$num);
$min=$a;
}
}
echo $min;

php array needed

hi all i need a snippet i know can do it with a bit of coding
but i need a snippet
i want an array of say choosable length like getArray(50) gives me a array of size 50
like we declare na ?
array[50] in other languages
and i want to fill it with some random data.
I want some real cool methods!
Like this
array(
0=>"sds"
1=>"bds"
....
n=>"mds"
);
You can get an array of a specific length, that is pre-filled with a given value, using the array_fill() function. I don't think that there is an in-built function that will generate arrays with random contents, though.
$myArray = array_fill(0, 50, null);
What form exactly do you want the array elements to take? You want them to be a lowercase letter frollowed by "ds"?
$myArraySize = 50;
$myArray = array_fill(0, $myArraySize, '_ds');
for ($i=0; $i<$myArraySize; $i++) {
$myArray[$i][0] = chr(mt_rand(97, 122));
}
this can be used to get array's of specific length filled with 24 character long string. Use it according to your use.
<?php
function generate_array($num)
{
$input = array();
$result = array_pad($input, $num, 0);
foreach($result as $key=>$val)
{
$result[$key] = gen_rand_str_24();
}
return $result;
}
function gen_rand_str_24()
{
return pack('N6', mt_rand(), mt_rand(), mt_rand(), mt_rand(), mt_rand(), mt_rand());
}
$result = generate_array(5);
print_r($result);
?>
Just do:
$arr = array();
$arr[] = "a";
$arr[] = "b";
Or similar:
$arr = array( 0 => "a",
1 => "b");
You don't need to set a length before filling it in PHP.

How to get numeric key of new pushed item in PHP?

$arr[] = $new_item;
Is it possible to get the newly pushed item programmatically?
Note that it's not necessary count($arr)-1:
$arr[1]=2;
$arr[] = $new_item;
In the above case,it's 2
end() do the job , to return the value ,
if its help to you ,
you can use key() after to petch the key.
after i wrote the answer , i see function in this link :
http://www.php.net/manual/en/function.end.php
function endKey($array){
end($array);
return key($array);
}
max(array_keys($array)) should do the trick
The safest way of doing it is:
$newKey = array_push($array, $newItem) - 1;
You can try:
max(array_keys($array,$new_item))
array_keys($array,$new_item) will return all the keys associated with value $new_item, as an array.
Of all these keys we are interested in the one that got added last and will have the max value.
You could use a variable to keep track of the number of items in an array:
$i = 0;
$foo = array();
$foo[++$i] = "hello";
$foo[++$i] = "world";
echo "Elements in array: $i" . PHP_EOL;
echo var_dump($foo);
if it's newly created, you should probably keep a reference to the element. :)
You could use array_reverse, like this:
$arr[] = $new_item;
...
$temp = array_reverse($arr);
$new_item = $temp[0];
Or you could do this:
$arr[] = $new_item;
...
$new_item = array_pop($arr);
$arr[] = $new_item;
If you are using the array as a stack, which it seems like you are, you should avoid mixing in associative keys. This includes setting $arr[$n] where $n > count($arr). Stick to using array_* functions for manipulation, and if you must use indexes only do so if 0 < $n < count($arr). That way, indexes should stay ordered and sequential, and then you can rely on $arr[count($arr)-1] to be correct (if it's not, you have a logic error).

Categories