I have this code:
public function get_names($number){
$names = array(
'None',
'Anton',
'bertha',
'Cesa',
'Dori',
'Egon',
'Frank',
'Gollum',
'Hans',
'Kane',
'Linus',
'Moose',
'Nandor',
'Oliver',
'Paul',
'Reese');
$bin = strrev(decbin($number));
$len = strlen($bin);
$output = array();
foreach(str_split($bin) as $key=>$char)
{
if ($key == sizeof($names)){
break;
}
if($char == 1)
{
array_push($output,$names[$key]);
}
}
return $output;
}
When I now call the function with number - let's say - 32256 I would get an array with "Kane, Linus, Moose, Nandor, Oliver, Paul".
Can anyone tell me what I would have to do when I want to give a certain names array and wanna get the number as a result where the certain bits are included? So exactly the other way around.
I found that code somewhere which works fine. But I need it vice versa.
Thanks in advance!
Andreas
EDIT: I want to know the decimal number when I e.g. have an array with "Anton, bertha,Cesa". I want to store those in a database instead of storing arrays with names each time. And when I need the names I just take the decimal number from database and use my function to get my name arrays.
If you just take the position in your $names array as being the bit position, you raise 2 to this position to give it the correct bit position and keep a running total of the items found...
$input = ["Cesa", "Gollum", "Hans"];
$output = 0;
foreach ( $input as $digit ) {
$output += pow(2,array_search($digit, $names ));
}
echo $output; // 392
with
$input = ["Kane", "Linus", "Moose", "Nandor", "Oliver", "Paul"];
gives
32256
Or as Barmar points out in his comment, you can save the lookup by inverting the names array using array_flip() which will mean that looking up each key will give the position in the array...
$output = 0;
$names = array_flip($names);
foreach ( $input as $digit ) {
$output += pow(2,$names[$digit]);
}
echo $output;
Related
I am trying to sort it in a repeating, sequential pattern of numerical order with the largest sets first.
Sample array:
$array = [1,1,1,2,3,2,3,4,5,4,4,4,5,1,2,2,3];
In the above array, I have the highest value of 5 which appears twice so the first two sets would 1,2,3,4,5 then it would revert to the second, highest value set etc.
Desired result:
[1,2,3,4,5,1,2,3,4,5,1,2,3,4,1,2,4]
I am pretty sure I can split the array into chunks of the integer values then cherrypick an item from each subarray sequentially until there are no remaining items, but I just feel that this is going to be poor for performance and I don't want to miss a simple trick that PHP can already handle.
Here's my attempt at a very manual loop using process, the idea is to simply sort the numbers into containers for array_unshifting. I'm sure this is terrible and I'd love someone to do this in five lines or less :)
$array = array(1,1,1,2,3,2,3,4,5,4,4,4,5,1,2,2,3);
sort($array);
// Build the container array
$numbers = array_fill_keys(array_unique($array),array());
// Assignment
foreach( $array as $number )
{
$numbers[ $number ][] = $number;
}
// Worker Loop
$output = array();
while( empty( $numbers ) === false )
{
foreach( $numbers as $outer => $inner )
{
$output[] = array_shift( $numbers[ $outer ] );
if( empty( $numbers[ $outer ] ) )
{
unset( $numbers[ $outer ] );
}
}
}
var_dump( $output );
I think I'd look at this not as a sorting problem, but alternating values from multiple lists, so rather than coming up with sets of distinct numbers I'd make sets of the same number.
Since there's no difference between one 1 and another, all you actually need is to count the number of times each appears. It turns out PHP can do this for you with aaray_count_values.
$sets = array_count_values ($input);
Then we can make sure the sets are in order by sorting by key:
ksort($sets);
Now, we iterate round our sets, counting down how many times we've output each number. Once we've "drained" a set, we remove it from the list, and once we have no sets left, we're all done:
$output = [];
while ( count($sets) > 0 ) {
foreach ( $sets as $number => $count ) {
$output[] = $number;
if ( --$sets[$number] == 0 ) {
unset($sets[$number]);
}
}
}
This algorithm could be adapted for cases where the values are actually distinct but can be put into sets, by having the value of each set be a list rather than a count. Instead of -- you'd use array_shift, and then check if the length of the set was zero.
You can use only linear logic to sort using php functions. Here is optimized way to fill data structures. It can be used for streams, generators or anything else you can iterate and compare.
$array = array(1,1,1,2,3,2,3,4,5,4,4,4,5,1,2,2,3);
sort($array);
$chunks = [];
$index = [];
foreach($array as $i){
if(!isset($index[$i])){
$index[$i]=0;
}
if(!isset($chunks[$index[$i]])){
$chunks[$index[$i]]=[$i];
} else {
$chunks[$index[$i]][] = $i;
}
$index[$i]++;
}
$result = call_user_func_array('array_merge', $chunks);
print_r($result);
<?php
$array = array(1,1,1,2,3,2,3,4,5,4,4,4,5,1,2,2,3);
sort($array);
while($array) {
$n = 0;
foreach($array as $k => $v) {
if($v>$n) {
$result[] = $n = $v;
unset($array[$k]);
}
}
}
echo implode(',', $result);
Output:
1,2,3,4,5,1,2,3,4,5,1,2,3,4,1,2,4
New, more elegant, more performant, more concise answer:
Create a sorting array where each number gets its own independent counter to increment. Then use array_multisort() to sort by this grouping array, then sort by values ascending.
Code: (Demo)
$encounters = [];
foreach ($array as $v) {
$encounters[] = $e[$v] = ($e[$v] ?? 0) + 1;
}
array_multisort($encounters, $array);
var_export($array);
Or with a functional style with no global variable declarations: (Demo)
array_multisort(
array_map(
function($v) {
static $e;
return $e[$v] = ($e[$v] ?? 0) + 1;
},
$array
),
$array
);
var_export($array);
Old answer:
My advice is functionally identical to #El''s snippet, but is implemented in a more concise/modern/attractive fashion.
After ensuring that the input array is sorted, make only one pass over the array and push each re-encountered value into its next row of values. The $counter variable indicates which row (in $grouped) the current value should be pushed into. When finished looping and grouping, $grouped will have unique values in each row. The final step is to merge/flatten the rows (preserving their order).
Code: (Demo)
$grouped = [];
$counter = [];
sort($array);
foreach ($array as $v) {
$counter[$v] = ($counter[$v] ?? -1) + 1;
$grouped[$counter[$v]][] = $v;
}
var_export(array_merge(...$grouped));
I am using a text file as little database, and each line has this format:
3692|Giovanni|giojo982|0005405
9797|Stefano|stefy734|45367
2566|Marco|markkkk998|355647689
4721|Roberto|robn88|809678741
I need to order them alphabetically maintaining their indexes, if it's possible.
At the moment, I'm using this code, but in this situation logically it doesn't work any more.
Reading this post How can I sort arrays and data in PHP? I have not found nothing similar to my scenario.
So, I'm wondering... is there a solution?
$db_friends = "db_friends.txt";
$dblines = file($db_friends);
if(isset($_GET['A-Z'])) {
asort($dblines);
}
if(isset($_GET['Z-A'])) {
arsort($dblines);
}
foreach($dblines as $key => $profile) {
list($uni_id, $name_surname, $textnum_id, $num_id) = explode("|", $profile);
echo $name_surname;
}
A-Z
Z-A
How can I solve it?
I assume by alphabetically that you're trying to sort alphabetically by the name in the second column. The problem is, asort() and arsort() perform too simple a comparison to deal with the type of data you're giving them. They're just going to see the rows as strings, and sort by the number in the first column. One way to address this is by splitting the rows before sorting.
$db_friends = "db_friends.txt";
$dblines = file($db_friends);
// split each line into an array
$dblines = array_map(function($line){
return explode('|', $line);
}, $dblines);
Then you can sort by the second column more easily. Using uasort(), you'll maintain the index association.
if (isset($_GET['A-Z'])) {
uasort($dblines, function(array $a, array $b) {
return strcmp($a[1], $b[1]);
});
}
if (isset($_GET['Z-A'])) {
uasort($dblines, function(array $a, array $b) {
return strcmp($b[1], $a[1]);
});
}
Obviously if you make that change, you'll no longer need to explode when you iterate the sorted array, as it was already done in the first step.
foreach ($dblines as $key => $profile) {
list($uni_id, $name_surname, $textnum_id, $num_id) = $profile;
echo $name_surname;
}
You can avoid the complexity of a uasort() call if you just position your columns in the order that you want to alphabetize them. This method has the added benefit of sorting all column data from left to right. This means, regardless of sorting direction (asc or desc), my method will sort $rows[0], then $row[1], then $row[2], then $row[3].
I have also logically combined your two if statements and set ASC as the default sorting direction.
Code: (Demo)
$txt=['9999|Marco|markkkk998|355647689','1|Marco|markkkk998|355647689','3692|Giovanni|giojo982|0005405','9797|Stefano|stefy734|45367','2566|Marco|markkkk998|355647689','4721|Roberto|robn88|809678741'];
foreach($txt as $row){
$values=explode('|',$row);
$rows[]=[$values[1],$values[0],$values[2],$values[3]]; // just reposition Name column to be first column
}
if(isset($_GET['Z-A'])) {
arsort($rows); // this will sort each column from Left-Right using Z-A
}else{
asort($rows); // (default) this will sort each column from Left-Right using A-Z
}
// var_export($rows);
foreach($rows as $i=>$profile) {
echo "$i {$profile[0]}\n"; // name value
}
Output:
2 Giovanni
1 Marco
4 Marco
0 Marco
5 Roberto
3 Stefano
If I understood your question, you could try this function:
function sortValuesKeepKey($lines) {
//declare arrays to be used temporarily
$idNumbers = array();
$values = array();
$return = array();
//loop through each line and seperate the number at the beginning
//of the string from the values into 2 seperate arrays
foreach($lines as $line) {
$columns = explode("|", $line);
$id = array_shift($columns);
$idNumbers[] = $id;
$values[] = implode("|", $columns);
}
//sort the values without the numbers at the beginning
asort($values);
//loop through each value and readd the number originally at the beginning
//of the string
foreach($values as $key => $value) {
//use $key here to ensure your putting the right data back together.
$return[$key] = $idNumbers[$key]."|".$values[$key];
}
//return finished product
return $return;
}
Just pass it the lines as an array and it should return it ordered properly.
If you want to sort the values by name_surname, see the below code
$db_friends = "db_friends.txt";
$dblines = file($db_friends);
// loop the lines
foreach($dblines as $key => $profile) {
// explode each line with the delimiter
list($uni_id, $name_surname, $textnum_id, $num_id) = explode("|", $profile);
// create an array with name_surname as a key and the line as value
$array[$name_surname] = $profile;
}
// bases on the GET paramater sort the array.
if(isset($_GET['A-Z'])) {
ksort($array); //sort acceding
}
if(isset($_GET['Z-A'])) {
krsort($array); // sort descending
}
// loop the sorted array
foreach($array as $key => $value) {
echo $key; // display the name_surname.
}
I store a number in a string. My code shuffles the digits into different permutations.
Example if the input is:
'123'
then the output permutations will be:
123,132,213,231,321,312
If the input string has repeated digits, my code does not work, and goes into an infinite loop.
Example inputs that don't work:
11,22,33,44,55,455,998,855,111,555,888,222 etc.
My code:
<?php
function factorial($n){
if($n==1) return $n;
return $n*factorial($n-1);
}
$a = '1234';
$_a = str_split($a);
$num = count($_a);
$ele_amnt = factorial($num);
$output = array();
while(count($output) < $ele_amnt){
shuffle($_a);
$justnumber = implode('', $_a);
if(!in_array($justnumber , $output))
$output[] = $justnumber;
}
sort($output);
print_r($output);
Can anyone explain why and how to fix it?
Short version: Your terminating condition for the while loop "is" permutational while your if(!in_array...) test "is" combinational.
Let's assume $a=11;: then $ele_amnt is 2 and your while loop will stop when the array $output contains more than one element.
Your shuffle/implode code can produce either the string <firstelement><seconelement> or <secondelement><firstelement>, both being 11.
And if(!in_array( $justnumber , $output)) allows only one of them to be appended to $output. So count($output) will be 1 after the first iteration and will stay 1 in perpetuity. Same for every $a with duplicate digits.
shuffle() changes the position of elements in an array at random. SO, the performance of the algorithm depends on ....luck ;-)
You might be interested in something like https://pear.php.net/package/Math_Combinatorics instead.
Your output array will contain less permutations if you have repeated characters in your input. So your loop never completes.
You could map your inputs, then later map back from your output, and then filter to do as you desire:
// For a string '122' we get the permutations of '123' first and then process.
$output = op_code_no_repeats('123');
$filtered = array();
foreach($output as $permutation) {
$filtered[] = str_replace('3', '2', $permutation);
}
$filtered = array_unique($filtered);
var_dump($filtered);
Outputs:
array (size=3)
0 => string '122' (length=3)
2 => string '212' (length=3)
3 => string '221' (length=3)
Your code with guards on the factorial and permutation functions:
function factorial($n)
{
if(! is_int($n) || $n < 1)
throw new Exception('Input must be a positive integer.');
if($n==1)
return $n;
return $n * factorial($n-1);
};
function op_code_no_repeats($a) {
$_a = str_split($a);
if(array_unique($_a) !== $_a)
throw new Exception('Does not work for strings with repeated characters.');
$num = count($_a);
$perms_count = factorial($num);
$output = array();
while(count($output) < $perms_count){
shuffle($_a);
$justnumber = implode('', $_a);
if(!in_array($justnumber , $output))
$output[] = $justnumber;
}
sort($output);
return $output;
}
I want to replace all array values with 0 except work and home.
Input:
$array = ['work', 'homework', 'home', 'sky', 'door']
My coding attempt:
$a = str_replace("work", "0", $array);
Expected output:
['work', 0, 'home', 0, 0]
Also my input data is coming from a user submission and the amount of array elements may be very large.
A bit more elegant and shorter solution.
$aArray = array('work','home','sky','door');
foreach($aArray as &$sValue)
{
if ( $sValue!='work' && $sValue!='home' ) $sValue=0;
}
The & operator is a pointer to the particular original string in the array. (instead of a copy of that string)
You can that way assign a new value to the string in the array. The only thing you may not do is anything that may disturb the order in the array, like unset() or key manipulation.
The resulting array of the example above will be
$aArray = array('work','home', 0, 0)
A loop will perform a series of actions many times. So, for each element in your array, you would check if it is equal to the one you want to change and if it is, change it. Also be sure to put quote marks around your strings
//Setup the array of string
$asting = array('work','home','sky','door')
/**
Loop over the array of strings with a counter $i,
Continue doing this until it hits the last element in the array
which will be at count($asting)
*/
for($i = 0; $i < count($asting);$i++){
//Check if the value at the 'ith' element in the array is the one you want to change
//if it is, set the ith element to 0
if ($asting[$i] == 'work' || $asting[$i] == 'home')
$asting[$i] = 0;
}
Here is some suggested reading:
http://www.php.net/manual/en/language.types.array.php
http://www.php.net/manual/en/language.control-structures.php
But if you are struggling on stuff such as looping, you may want to read some introductory programming material. Which should help you really understand what's going on.
A bit other and much quicker way, but true, need a loop:
//Setup the array of string
$asting = array('bar', 'market', 'work', 'home', 'sky', 'door');
//Setup the array of replacings
$replace = array('home', 'work');
//Loop them through str_replace() replacing with 0 or any other value...
foreach ($replace as $val) $asting = str_replace($val, 0, $asting);
//See what results brings:
print_r ($asting);
Will output:
Array
(
[0] => bar
[1] => market
[2] => 0
[3] => 0
[4] => sky
[5] => door
)
An alternative using array_map:
$original = array('work','home','sky','door');
$mapped = array_map(function($i){
$exclude = array('work','home');
return in_array($i, $exclude) ? 0 : $i;
}, $original);
you may try array_walk function:
function zeros(&$value)
{
if ($value != 'home' && $value != 'work'){$value = 0;}
}
$asting = array('work','home','sky','door','march');
array_walk($asting, 'zeros');
print_r($asting);
You can also give array as a parameter 1 and 2 on str_replace...
Just a small point to the for loop. Many dont realize the second comparing task is done every new iteration. So if it was a case of big array or calculation you could optimize loop a bit by doing:
for ($i = 0, $c = count($asting); $i < $c; $i++) {...}
You may also want to see http://php.net/manual/en/function.array-replace.php for original problem unless the code really is final :)
Try This
$your_array = array('work','home','sky','door');
$rep = array('home', 'work');
foreach($rep as $key=>$val){
$key = array_search($val, $your_array);
$your_array[$key] = 0;
}
print_r($your_array);
There are a few techniques on this page that make zero iterated function calls -- which is good performance-wise. For best maintainability, I recommend separating your list of targeted string as a lookup array. By modifying the original array values by reference, you can swiftly replace whole strings and null coalesce non-targeted values to 0.
Code: (Demo)
$array = ['work', 'homework', 'home', 'sky', 'door'];
$keep = ['work', 'home'];
$lookup = array_combine($keep, $keep);
foreach ($array as &$v) {
$v = $lookup[$v] ?? 0;
}
var_export($array);
Output:
array (
0 => 'work',
1 => 0,
2 => 'home',
3 => 0,
4 => 0,
)
You can very easily, cleanly extend your list of targeted strings by merely extending $keep.
If you don't want a classic loop, you can use the same technique without modifying the original array. (Demo)
var_export(
array_map(fn($v) => $lookup[$v] ?? 0, $array)
);
this my final code
//Setup the array of string
$asting = array('work','home','sky','door','march');
/**
Loop over the array of strings with a counter $i,
Continue doing this until it hits the last element in the array
which will be at count($asting)
*/
for($i = 0; $i < count($asting); $i++) {
//Check if the value at the 'ith' element in the array is the one you want to change
//if it is, set the ith element to 0
if ($asting[$i] == 'work') {
$asting[$i] = 20;
} elseif($asting[$i] == 'home'){
$asting[$i] = 30;
}else{
$asting[$i] = 0;
}
echo $asting[$i]."<br><br>";
$total += $asting[$i];
}
echo $total;
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.