array_rand not working as expected in PHP - php

I was playing around with PHP as I've just begun my training in it. I came across the array_rand function that returns random indexes and you can control how many random indexes you want. But what if the number of random indexes is kept equal to the actual length of the array? I tried it and the result was surprising.
<?php
$arr = array(1,2,3,4,5,6);
$temp = array_rand($arr,6);
foreach($temp as $r){
echo $arr[$r]." ";
}
?>
So, I'm randomizing all the indices and printing the same array once again, but in the order that array_rand returns. Please note that I'm not looking for an alternative for this piece of code as I was solely practicing. What I want to know is why the random function returns Array ( [0] => 0 [1] => 1 [2] => 2 [3] => 3 [4] => 4 [5] => 5 ) [if you print the array_rand result]? Why is it not random in this case?

array_rand is to pick some random indexes from a given array. For example it may gives you 1,3,4 indexes or 3,5,6 indexes. But not 5,2,4 (At least the purpose of the function is not that).
If you want to randomize indexes for an array you have to use shuffle
http://php.net/manual/en/function.shuffle.php

Just add one more step after arry_rand, shuffle(); so your code will be:
<?php
$arr = array(1,2,3,4,5,6);
$temp = array_rand($arr,6);
shuffle($temp);
foreach($temp as $r){
echo $arr[$r]." ";
}
?>
because as pre. answer explained the mean.

Related

Fatal error: Allowed memory size exhausted while looping through a 14 element long single-character-array

I have a simple string. I need to produce an output Array such that the order of every 2 consecutive characters is reversed.
Input string is 14f05000034e69 and I need the following output Array [4, 1, 0, f, 0, 5, 0, 0, 4, 3, 6, e, 9, 6].
Here is my PHP code:
$myString = "14f05000034e69";
$myStringArray = str_split($myString);
$newArray = array();
for ($index=0; $index<count($myStringArray)-1; $index+2) {
$newArray[] = $myStringArray[$index+1];
$newArray[] = $myStringArray[$index];
}
print_r($newArray);
And it is giving me
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 134217736 bytes) in /var/www/html/test.php on line 8
The question is why and how do I fix it?
<?php
$myString = "14f05000034e69";
$myStringArray = str_split($myString);
$i=0;
foreach($myStringArray as $row){
if(array_key_exists($i,$myStringArray)) {
$newArray[$i] = $myStringArray[$i + 1];
$newArray[$i + 1] = $myStringArray[$i];
$i = $i + 2;
}
}
echo '<pre>';
print_r($newArray);
I found a workaround in a bit "dirty" way but i managed to do what you asked.
Basically i split the string like you did but i play with the new array positions around and push in my new array the positions that i want to that's why i used a counter for that.
The output is:
Array
(
[0] => 4
[1] => 1
[2] => 0
[3] => f
[4] => 0
[5] => 5
[6] => 0
[7] => 0
[8] => 3
[9] => 0
[10] => e
[11] => 4
[12] => 9
[13] => 6
)
Basically i thought that i need to loop the array by two but every time i loop i need to handle 2 array positions and then the next two.
So that led me to handle my $new_array in a way that i push at the same time data in the current position i am and in the next position, that's why the counter $i+1 is used to handle array position.
If i did not use it there and used simple $newArray[] it would put the data in my current position and overwrite it again in the second step and also i could not move my array pointer to positions 1,3,5,6 etc etc that's why i am "forcing" it to use my $i counter so i keep pointing every after position.
My $i counter is set at the end of each loop to move with step 2.
The shortest alternative I could come up with is to use some of the array methods instead...
$myString = "14f05000034e69";
$out = str_split(implode(array_map ('strrev', str_split($myString, 2))));
print_r( $out );
This uses str_split() to split it into 2 char chunks, then uses array_map() and strrev() to reverse each item and then implode() to put them all back again.
The outer call to str_split() just splits the result back down to 1 char elements in an array for the output (miss this off if you just need the string itself)
In my opinion, the str_split is redundant in this operation, strings can be iterated through as of arrays, like this:
$myString = "14f05000034e69";
$newArray = array();
for ($index=0; $index<strlen($myString)-1; $index+=2)
{
$newArray[] = $myString[$index+1];
$newArray[] = $myString[$index];
}
print_r($newArray);
But yeah, as said before, just missing += in the for loop.
I made a small test on regex to see if it could be done, works as a charm. But of course, I only deliver a string in this case. :)
$myString = "14f05000034e69";
$test = preg_replace('/(.)(.)/', '$2$1', $myString);
echo $test;
This is the most elegant solution I could come up with.
Code tested here: https://3v4l.org/mtdca
And for the regex: https://3v4l.org/nI4UP
An answer has already been marked as the solution an many other answers too however I think this can help to know that we can achieve the inversion in the string itself and then split it.If an array is not needed we can just keep the string.This way we use less memory i think:
$myString = "14f05000034e69";
$length=strlen($myString);
for ($index=-1, $length=$length%2==0?$length-1:$length-2; $index<$length-1; $index+=2) {
$tmp=$myString[$index+1];
$myString[$index+1]=$myString[$index+2];
$myString[$index+2]=$tmp;
}
print_r(str_split($myString));// return an array
print_r($myString); //here a string
This can handle variable length of strings

get ordinal value for letter PHP

I've been given a datafile where the original creator used alphabetical rather than numeric values to show order.
For example, if there's ten items, they'd be named:
12342313A
12342313B
12342313C
12342313D
12342313E
...
I need to import these values into a mySQL table that has order as a required int column, and I need to convert the letter to a number.
Is there a function in PHP to get a numeric value for a letter? Or will I need to do a substr to grab the trailing letter, and create an indexed array of letters and just do a lookup against that array?
I'm hesitant to do the simple way above, since I don't know how many objects could potentially exist, and I could need to write an array from A-AAAA or something.
Try converting it from base 36 to base 10 using base_convert(), I.e. base_convert($str, 36, 10). You might need to strtolower it first, and it'll only work if its not case sensitive.
PHP has a simple way to create that array, so you could write a function to figure all that out for you and do something like:
function str_to_num($letters, $max = 'ZZZZZZ') {
$count = 0;
for ($i = 'A'; $i < $max; $i++) {
$count++;
if ($letters == $i)
return $count;
}
}
Then you could do the substr, find the letters at the end, and then pass it into the function:
str_to_num('A'); // returns 1
str_to_num('AB'); // returns 28
str_to_num('AC'); // returns 29
str_to_num('ABC'); // returns 731
Something like that, anyway.
Good luck.
Assuming this is a one-time problem that you've got to correct and won't encounter moving forward, I suggest you use sort to... erm, sort out the problem. Let's say you have all those alpha-numeric order fields in an array, like so:
$vals = array (
'12342313A',
'12342313D',
'12342313E',
'12342313B',
'12342313C'
);
Those are all mixed up, not in order. But, you can call the function sort (docs) on that array and PHP does a decent job of making sense out of it:
print '<pre>Unsorted: ';
print_r($vals);
print '</pre>';
sort($vals);
print '<pre>Sorted: ';
print_r($vals);
print '</pre>';
/*
Unsorted: Array
(
[0] => 12342313A
[1] => 12342313D
[2] => 12342313E
[3] => 12342313B
[4] => 12342313C
)
Sorted: Array
(
[0] => 12342313A
[1] => 12342313B
[2] => 12342313C
[3] => 12342313D
[4] => 12342313E
)
*/
So far, so good. Now, you've got them ordered, and as a bonus you can use the index of the array as your new field in the database. Alter the table and add a field to hold the new value; we'll call this field numeric_order, and in my sample I've called the field that currently holds the alpha-numeric sort data string_order. Loop your sorted array and update the database (for example):
foreach ($vals as $x=>$v) {
$sql = 'UPDATE myTable SET numeric_order = '.($x+1).' WHERE string_order = "'.$v.'"';
}
I add 1 to x in the loop based on the assumption that you don't want anything to have 0 for the order - if that isn't a concern, then you can just use x. This is also predicated on the assumption that no two rows have the same alpha-numeric sort value.
If they do, then all is not lost! Start with your array looking like this:
$vals = array (
3=>'12342313A',
15=>'12342313D',
66=>'12342313E',
101=>'12342313B',
200=>'12342313C'
);
... the numeric keys would represent the unique/primary key of the corresponding row. Instead of sort, which does not preserve keys, use asort (which does preserve keys - docs), and then your loop looks like this:
$ord = 1
foreach ($vals as $x=>$v) {
$sql = 'UPDATE myTable SET numeric_order = '.$ord.' WHERE id = "'.$x.'"';
$ord++;
}
If my base assumption is wrong, and you'll continue to deal with this method of ordering rows, then in my humble view you ought to re-consider your data design.
use ord() with substr and subtract 64. This will set A to 1, B to 2, etc...
From what you have above, it seems like your values (last digit, at least) can be thought as being hex numbers. You can then transform them into decimal numbers through the hexdec function.
http://php.net/manual/en/function.hexdec.php

Splitting an array equally:

I have the following array:
$array = array(1,0,0,0,1,1,1,1,0,1,1,1,1,0,1,1,0,1,0,0,1,0,1);
I want split it up into individual arrays so that each array contains seven or less values.
So for example the first array will become:
$one = array(1,0,0,0,1,1,1)
$two = array(1,0,1,1,1,1,0)
$three = array(1,1,0,1,0,0,1);
$four = array(0,1);
Also how would you count the number of times 1 occurs in array one?
array_chunk() is what you are looking for.
$splitted = array_chunk($array, 7);
For counting the occurences I would be lazy. If your arrays only contain 1s or 0s, then a simple array_sum() would do:
print array_sum($splitted[0]); // for the first chunk
I want split it up into individual arrays so that each array contains seven or less values.
Use array_chunk(), which is made expressly for this purpose.
Also how would you count the number of times 1 occurs in array one?
Use array_count_values().
$one = array(1,0,0,0,1,1,1);
$one_counts = array_count_values($one);
print_r($one_counts);
// prints
Array
(
[0] => 3
[1] => 4
)
Assuming you want to preserve the contents of the array, I'd use array_slice() to extract the needed number of elements from the array, incrementing the '$offset' by the required count each time until the array was exhausted.
And as to your second question, try:
$num_ones=count(preg_grep(/^1$/,$array));

How to sort an array in php

i want the same value has the same index
for example
1 2 2 3 5
after sort:
array(
0=>1
1=>2
1=>2
3=>3
4=>5);
but we can not set duplicate index in the array of php.
There's a sort function in php! ( I answer the topic and not the body, didn't quite follow you there, but here's how you sort in php )
Example
<?php
$fruits = array("lemon", "orange", "banana", "apple");
sort($fruits);
foreach ($fruits as $key => $val) {
echo "fruits[" . $key . "] = " . $val . "\n";
}
?>
Duplicates
In the above example duplicates will just have their own indexes so the array:
5 4 5 1 3 1 2
Will look like this
1 1 2 3 4 5 5
This might not be what you are looking for, what you want is another type of dataset than just a simple array, maybe you want a hashtable or just a linked list on each row.
If you are okay with it, you can remove the duplicates by using array_unique
$newArray=array_unique($arr);
Which would lead to having an array looking like this
1 2 3 4 5
You're right, you can't have duplicate values at the same index in an array - each index in an array has exactly one value.
As to the title of the question, to sort an array in PHP, use sort.
If this doesn't answer what you're trying to ask, you might want to edit your question to make it a bit clearer (the body of the question doesn't seem particularly related to the question title).
Post OP's edit:
You cannot store multiple values at the same key, your output array (array(0=>1, 1=>2, 1=>2, 3=>3, 4=>5);) doesn't really make sense (the key 1 does map to the value 2) in the sorted array. Are you trying to store counts of occurrences of numbers?
e.g. given the input:
1, 2, 2, 3, 5
get the output:
array(1=>1, 2=>2, 3=>1, 5=>1); // there is 1 "1", there are 2 "2"s etc.
Try to use this.
sort($array);
You are looking for array_unique:
array array_unique ( array $array [, int $sort_flags = SORT_STRING ] )
Takes an input array and returns a new array without duplicate values.

php array processing question

Before I write my own function to do it, is there any built-in function, or simple one-liner to convert:
Array
(
[0] => pg_response_type=D
[1] => pg_response_code=U51
[2] => pg_response_description=MERCHANT STATUS
[3] => pg_trace_number=477DD76B-B608-4318-882A-67C051A636A6
)
Into:
Array
(
[pg_response_type] => D
[pg_response_code] =>U51
[pg_response_description] =>MERCHANT STATUS
[pg_trace_number] =>477DD76B-B608-4318-882A-67C051A636A6
)
Just trying to avoid reinventing the wheel. I can always loop through it and use explode.
I can always loop through it and use explode.
that's what you should do.
Edit - didn't read the question right at all, whoops..
A foreach through the array is the quickest way to do this, e.g.
foreach($arr as $key=>$val)
{
$new_vals = explode("=", $val);
$new_arr[$new_vals[0]] = $new_vals[1];
}
This should be around five lines of code. Been a while since I've done PHP but here's some pseudocode
foreach element in the array
explode result on the equals sign, set limit = 2
assign that key/value pair into a new array.
Of course, this breaks on keys that have more than one equals sign, so it's up to you whether you want to allow keys to have equals signs in them.
You could do it like this:
$foo = array(
'pg_response_type=D',
'pg_response_code=U51',
'pg_response_description=MERCHANT STATUS',
'pg_trace_number=477DD76B-B608-4318-882A-67C051A636A6',
);
parse_str(implode('&', $foo), $foo);
var_dump($foo);
Just be sure to encapsulate this code in a function whose name conveys the intent.

Categories