How to reorder this array in a specific order? - php

I have this string of random numbers that needs to have some of the integers converted into letters. Notice that it takes two positions in the string to make a letter.
01110413 Original string
This string should ultimately be converted into this:
A11D13 Converted string
Here is my code so far
$id = '01110413';
$chg = array(0 => array(0, 1), 3 => array(4, 5));
$ltr = array(00 => 'A', 01 => 'B', 03 => 'C', 04 => 'D');
$id = str_split($id);
foreach($chg as $ltrpos => $val){
// $ltrpos; letter position placement in string AFTER conversion to letter
$ltrkey = null;
foreach($val as $idkey){
$ltrkey .= $id[$idkey];
unset($id[$idkey]);
if(!empty($ltrkey)){
$out[$ltrpos] = $ltr[(INT)$ltrkey];
}
}
}
Running this code gives:
Array
(
[0] => B
[3] => D
)
I need to insert these new values in the place where the old integer values were. The $chg array key is the position where the values should be in the converted string.
How can I order my final $out array so that the integers that were unset are replaced with the converted letters in their place?

This should do it:
$id = '01110413';
// your string codes always take up two positions, so you just need to provide the final position in the string
$chg = array(0,3);
// You could actually change 00 to just 0 (since they're integers). Also, later in the script, the two character position is cast to an int, so it will match these values.
$ltr = array(00 => 'A', 01 => 'B', 03 => 'C', 04 => 'D');
$converted_id = doConvert($id, $ltr, $chg);
function doConvert($id, $conversion_codes, $final_position) {
if( count($final_position) == 0 ) return $id;
$next_pos = array_shift($final_position);
// convert the two characters at the next position to a letter
$id = substr($id, 0, $next_pos) . $conversion_codes[(int) substr($id, $next_pos, 2)] . substr($id, $next_pos+2); // (cast to an (int) so it will match the keys in our conversion array)
return doConvert($id, $conversion_codes, $final_position);
}
Output of this example is:
B11D13
You say the first value should be A, but 01 => B, that's why the first letter is B.

If every two characters in your original id is a code, you can use something more general, like this:
$id = '01110413';
$conversion = array('00' => 'A', '01' => 'B', '03' => 'C', '04' => 'D');
$converted_id = "";
for($i=0; $i < strlen($id); $i+=2) {
$char_code = substr($id, $i, 2);
// we don't know this code, just append it
if( empty($conversion[$char_code]) ) {
$converted_id .= $char_code;
}
// convert and append
else {
$converted_id .= $conversion[$char_code];
}
}

Related

PHP Array split string and Integers

Below is an array of strings and numbers. How could the string and number values be split into separate arrays (with strings in one array and numbers in another array)?
array('a','b','c',1,2,3,4,5,'t','x','w')
You could also do this in one line using array_filter()
$numbers = array_filter($arr,function($e){return is_numeric($e);});
$alphas = array_filter($arr,function($e){return !is_numeric($e);});
print_r($numbers);
print_r($alphas);
Loop through them, check if is_numeric and add to appropriate array:
$original = array('a','b','c',1,2,3,4,5,'t','x','w');
$letters = array();
$numbers = array();
foreach($original as $element){
if(is_numeric($element)){
$numbers[] = $element;
}else{
$letters[] = $element;
}
}
https://3v4l.org/CAvVp
Using a foreach() like in #jnko's answer will be most performant because it only iterates over the array one time.
However, if you are not concerned with micro-optimization and prefer to write concise or functional-style code, then I recommend using array_filter() with is_numeric() calls, then making key comparisons between the first result and the original array.
Code: (Demo)
$array = ['a','b',0,'c',1,2,'ee',3,4,5,'t','x','w'];
$numbers = array_filter($array, 'is_numeric');
var_export($numbers);
var_export(array_diff_key($array, $numbers));
Output:
array (
2 => 0,
4 => 1,
5 => 2,
7 => 3,
8 => 4,
9 => 5,
)
array (
0 => 'a',
1 => 'b',
3 => 'c',
6 => 'ee',
10 => 't',
11 => 'x',
12 => 'w',
)
$data = array('a','b','c',1,2,3,4,5,'t','x','w');
$integerArray = array();
$stringArray = array();
$undefinedArray = array();
foreach($data as $temp)
{
if(gettype($temp) == "integer")
{
array_push($integerArray,$temp);
}elseif(gettype($temp) == "string"){
array_push($stringArray,$temp);
}else{
array_push($undefinedArray,$temp);
}
}

How to start looping through an array at a different index and finishing the entire array

I am trying to figure out how I can start looping through an array at a different index but when it reaches the end it loops back to the beginning and finishes the array. Basically, I need to be able to dynamically change the offset of the array.
What I am trying to do it associate a letter of the alphabet with a different alphabet letter to mix things up for a string.
Let's say I have a random array like so
$arr = array('a' => 'g', 'b' => 'w', 'c' => 'j', 'd' => 'y', 'e' => 'k');
Then I have a string like so
$string = 'abcde';
And let's say I need to start at index in the array at 2 which would be 'c' => 'j' then finish the array to the end and then loop back to the beginning until it is finished.
What I want to do is replace each letter with the corresponding letter associated with it in the array. So the final string after it is replaced would look like
I would reconstruct the array with
$build = strtr($string,$arr);
which would echo gwjyk
But I need to start at a random point in the array and then finish it and go back to the beggining and finish the entire array.
So maybe I have an offset of 2.
$offset = 2;
As I mentioned in the comments, I would approach this using array_slice and then merging the two arrays in order to simply get a new array, then loop through it from start to finish.
Here's a fully functional solution (and a runnable version)- although I'd like to point out that the offset really doesn't change the results at all:
/**
* Goes through a string and replaces letters based on an array "map".
*
* #param string - $string
* #param int - $offset
*
* #return string
*/
function change_letters( $string, $offset ) {
$letters = ['a' => 'g', 'b' => 'w', 'c' => 'j', 'd' => 'y', 'e' => 'k'];
// some defensive code to prevent notices or errors
if ( (int)$offset > count($letters)) {
echo '<p>Error: Offset is larger than the array of letters!</p>';
return $string;
}
// build new array based on passed-in offset
$new_array = array_slice($letters, $offset) + array_slice($letters, 0, $offset);
// at this point, array is ['c' => 'j', 'd' => 'y', 'e' => 'k', 'a' => 'g', 'b' => 'w']
// loop through the letters to replace...
foreach($new_array AS $from => $to) {
// swaps all instances of the "from" letter to the "to" letter in the string.
// NOTE: this could be easily modified to only replace n instances of the "from" letter
// like so: $string = str_ireplace( $from, $to, $string, 1); - would only replace 1 instance
$string = str_ireplace( $from, $to, $string );
}
return $string;
}
// Sample usage:
$word = 'abcde';
$new_word = change_letters( $word, 2); // "gwjk"
var_dump(2, $new_word);
$new_word = change_letters( $word, 5); // "gwjk"
var_dump(5, $new_word);
$new_word = change_letters( $word, 6); // "abcde"
var_dump(5, $new_word);
You can try:
<?php
$arr = array(1 => 2, 3 => 4, 5 => 6, 7 => 8, 9 => 0);
$STARTING_KEY = 3;
$array_keys = array_keys($arr);
$starting_index = array_search($STARTING_KEY, $array_keys);
for ($i = $starting_index; $i < sizeof($arr); $i++) {
echo $arr[$array_keys[$i]] . "\n";
}
for ($i = 0; $i < $starting_index; $i++) {
echo $arr[$array_keys[$i]] . "\n";
}
This will test all possible offsets for the string
$arr = array('a' => 'g', 'b' => 'w', 'c' => 'j', 'd' => 'y', 'e' => 'k');
$str = "abcde";
$strlen = strlen($str);
$keys = array_keys($arr);
for ($j = 0; $j < $strlen; $j++)
{
$startIndex = $j;
echo "offset: " . $startIndex . ": ";
for ($i = $startIndex; $i < $strlen; $i++ )
{
$char = substr( $str, $i, 1 );
echo $arr[$char];
}
for ($i = 0; $i < $startIndex; $i++ )
{
$char = substr( $str, $i, 1 );
echo $arr[$char];
}
echo "\n";
}
Output:
offset: 0: gwjyk
offset: 1: wjykg
offset: 2: jykgw
offset: 3: ykgwj
offset: 4: kgwjy
As mentioned in the comment, another option for your example data could be using array_slice and setting the offset and the length parameters and use array_merge:
$arr = array('a' => 'g', 'b' => 'w', 'c' => 'j', 'd' => 'y', 'e' => 'k');
$top = array_slice($arr, 0, 2);
$rest = array_slice($arr, 2);
print_r(array_merge($rest, $top));
Array
(
[c] => j
[d] => y
[e] => k
[a] => g
[b] => w
)
All that array slicin’n’dicing or using two loops to loop from x to end first, and start up to x second, is fine … but they don’t make for the most readable code IMHO.
Such an “offsetted circling-through” can be achieved in a quite trivial way with a numerically indexed array - a simple for loop, and the index “clamped down” by using modulo with the total number of array elements.
So in a case like this, I would perhaps prefer the following approach:
$arr = array('a' => 'g', 'b' => 'w', 'c' => 'j', 'd' => 'y', 'e' => 'k');
$c = count($arr);
$search = array_keys($arr);
$replace = array_values($arr);
$offset = 2; // zero-based
for( $i = 0; $i < $c; ++$i ) {
$idx = ( $i + $offset ) % $c;
echo $search[$idx] . ' => ' . $replace[$idx] . "<br>\n";
}
// result:
// c => j
// d => y
// e => k
// a => g
// b => w

How to encode binary to a DNA sequence

I would like to encode a binary sequence to a DNA sequence by following this rule:
00 = A
01 = C
10 = G
11 = T
For example: 10011100 = GCTA.
I wrote a PHP script which converts my string to binary and then I convert the binary to a DNA sequence by using the str_replace function. My issue is that the DNA sequence is not correctly converted. Can someone help me?
Here's my PHP script:
<?php
// Function to convert string to bin
function strToBin($input) {
if (!is_string($input))
return false;
$ret = '';
for ($i = 0; $i < strlen($input); $i++) {
$temp = decbin(ord($input{$i}));
$ret .= str_repeat('0', 8 - strlen($temp)) . $temp;
}
return $ret;
}
$bin = strToBin('Stack');
// Try to transcript binary to DNA
$bincomb = array('00', '01', '10', '11');
$DNAtrans = array('A', 'C', 'G', 'T');
echo $transcript = str_replace($bincomb, $DNAtrans, $bin);
?>
The str_replace() approach doesn't work because it looks for the substrings in the order 00, 01, 10, 11. So, for example, with the binary string 1001 it replaces the inner 00 with an A, after which the string is 1A1, and no more conversions can be made.
For your function to work, you need to go through the binary string in chunks of two characters.
$bin = strToBin('Stack');
$bin = str_split($bin, 2);
$combine = array(
'00' => 'A',
'01' => 'C',
'10' => 'G',
'11' => 'T'
);
$str = '';
foreach ($bin as $item)
$str .= $combine[$item];
The string is first split into chunks of two characters, which are then looped through and their respective values appended to the result string $str.
In PHP, I usually do these transformations with the two-arguments implementation of strtr(), like this:
// outputs 10011100
echo strtr("GCTA", array("A" => "00", "C" => "01", "G" => "10", "T" => "11"));
The reverse is also possible:
// outputs GCTA
echo strtr("10011100", array("00" =>"A", "01" => "C", "10" => "G", "11" => "T"));

php display random value from key on array

I have array which have in letter format key.
'A' => array('WORD1','WORD2','WORD3'),
'B' => array('WORD1','WORD2','WORD3'),
'C' => array('WORD1','WORD2','WORD3'),
'D' => array('WORD1','WORD2','WORD3'),
'E' => array('WORD1','WORD2','WORD3'),
'F' => array('WORD1','WORD2','WORD3'),
'H' => array('WORD1','WORD2','WORD3'),
'G' => array('WORD1','WORD2','WORD3'),
...
I need to pick random value from each element. Example, when I set $output = "FGH"
Output will be:
F - (RANDOM WORD FROM ARRAY KEY F)\n
G - (RANDOM WORD FROM ARRAY KEY F)\n
H - (RANDOM WORD FROM ARRAY KEY H)\n
I used my code below but doesn't work..
$result = array();
foreach($chars as $char){
$random_key = array_rand($words[$char]); // get random key
$key = $words[$char][$random_key]; // get the word
unset($words[$char][$random_key]); // unset it so that it will never be repeated
$result[$key] = $char; // push it inside
}
Thanks to anyone that would help me
This gives a random word from whichever keys are specified in $output (note I have modified your $chars array slightly to make it obvious which value is being returned):
$chars = array(
'A' => array('A_WORD1','A_WORD2','A_WORD3'),
'B' => array('B_WORD1','B_WORD2','B_WORD3'),
'C' => array('C_WORD1','C_WORD2','C_WORD3'),
'D' => array('D_WORD1','D_WORD2','D_WORD3'),
'E' => array('E_WORD1','E_WORD2','E_WORD3'),
'F' => array('F_WORD1','F_WORD2','F_WORD3'),
'G' => array('G_WORD1','G_WORD2','G_WORD3'),
'H' => array('H_WORD1','H_WORD2','H_WORD3')
);
$output = 'FGH';
$result = array();
foreach(str_split($output) as $key) {
$result[] = $chars[$key][array_rand($chars[$key])];
}
var_dump($result);
The secret sauce here is the str_split() function.
<?php
$a=array("red","green","blue","yellow","brown");
$random_keys=array_rand($a,3);
echo $a[$random_keys[0]]."<br>";
echo $a[$random_keys[1]]."<br>";
echo $a[$random_keys[2]];
?>
for your reference : http://php.net/manual/en/function.array-rand.php
If you have already set up the random arrays to pick words from, it's quite straight forward with count() and rand().
//$globalWordArray = .......;
$selectedArray = array('B','D','F');
$wordList = array();
foreach($selectedArray as $words){
$wordList[] = $globalWordArray[$words][rand(0,count($globalWordArray[$words])-1];
}
This could be a solution:
$letters = array(
'A' => array('WORD1','WORD2','WORD3'),
'B' => array('WORD1','WORD2','WORD3'),
'C' => array('WORD1','WORD2','WORD3'),
'D' => array('WORD1','WORD2','WORD3'),
'E' => array('WORD1','WORD2','WORD3'),
'F' => array('WORD1','WORD2','WORD3'),
'H' => array('WORD1','WORD2','WORD3'),
'G' => array('WORD1','WORD2','WORD3'),
);
$output = "FGH";
for ($i=0; $i < strlen($output); $i++) {
echo $output[$i] ." - (RANDOM WORD FOR ARRAY KEY " . $output[$i]." ";
echo $letters[$output[$i]][array_rand($letters[$output[$i]])] .")" . "<br />";
}
Output is:
F - (RANDOM WORD FOR ARRAY KEY F WORD3)
G - (RANDOM WORD FOR ARRAY KEY G WORD3)
H - (RANDOM WORD FOR ARRAY KEY H WORD1)
Your logic looks wrong where you are actually performing the randomisation, see comments in your code below
$result = array();
foreach($chars as $char){
$random_key = array_rand($words[$char]);
$key = $words[$char][$random_key]; // This is a value at this point yet you named it key
unset($words[$char][$random_key]);
$result[$key] = $char; // This will create an entry in result such as $result['WORD 1'] = 'F', I'm sure thats wrong
}
Fixed version below
$result = array();
foreach($chars as $char){
$random_key = array_rand($words[$char]);
$value = $words[$char][$random_key];
unset($words[$char][$random_key]);
$result[$char] = $value;
}
What you have suggested you want is commonly referred to as a Shuffle Bag (http://kaioa.com/node/89). Shuffle Bags allow you to fill up collections with items and then pick them out randomly until the collection runs out of items. Think of it like the Bag of letters in Scrabble. There is a PHP implementation in the link above.
Using that sort of implementation would turn your foreach loop to this:
$result = array();
foreach($chars as $char){
$result[$char] = $words[$char]->next();
}

How to find the first free key in an array

We all know that arrays are actually ordered trees in PHP. Given that, an array index (integer key) need not be in any strict order or even exist at all. So, given an array like:
array( 1 => 'A', 5 => 'B', 2 => 'C', 3 => 'D', 6 => 'E', 0 => 'F' )
How can we determine the lowest (non negative) integer of the first empty key, without re-indexing the array? In this case it would be 4.
Easy solution by while loop:
function firstFreeKey($array)
{
$i = 0;
while(isset($array[$i])) $i++;
return $i;
}
$array = array( 1 => 'A', 5 => 'B', 2 => 'C', 3 => 'D', 6 => 'E', 0 => 'F' );
echo firstFreeKey($array);
Output:
4
$a = array( 1 => 'A', 5 => 'B', 2 => 'C', 3 => 'D', 6 => 'E', 0 => 'F' );
for($i = 0, $l = count($a); $i < $l; $i++) if(!array_key_exists($i, $a)) break;
echo $i; // 4
First method is getting fancy with arrays.
// STUPID FANCY WAY (playing with arrays)
$array = array( 1 => 'A', 5 => 'B', 2 => 'C', 3 => 'D', 6 => 'E', 0 => 'F' );
// fetch existing keys
$keys = array_keys($array);
// build a range with all keys (between min and max)
$keys_all = range(min($keys), max($keys));
// difference between all and existing
$keys_diff = array_diff($keys_all, $keys);
// fetch the first in difference (min)
$min_key = reset($keys_diff);
// output it
var_dump($min_key);
Second method is actually viable as it spares the need for extra arrays in memory.
// PROPER WAY (not extra array operations)
$array = array( 1 => 'A', 5 => 'B', 2 => 'C', 3 => 'D', 6 => 'E', 0 => 'F' );
// fetch existing keys
$keys = array_keys($array);
// nullify first
$min_key = null;
// loop all keys and find missing one (skip 1st and last, they totally exist!)
for($key = ($min = min($keys)) + 1, $max = max($keys); $key < $max; ++$key){
if(!isset($array[$key])){
$min_key = $key;
break;
}
}
// output it
var_dump($min_key);
I'll explain if comments are not enough.
PS: This method handles situation when minimum key value is not 0. Hence it's independent of range min and max. And keys need to be integers, obviously.
Have you tried something like
echo min(array_keys($array));
array_keys returns the list of keys for the array, and min determines the lowest value in the array.
Expanding following comments :
As the array is a continous int value, you can do the following
$keys = array_keys($array);
$arr2 = range(0,max($keys));
// diff gets the missing elements
$missing = array_diff($arr2,$keys);
echo $missing[0];
Not sure on the performance of this vs brute force, but it can be tested.
Possibly one of the longest answers, but the most explained.
$Jumbled_Arr = array(
1 => "test",
3 => "another",
4 => "t",
7 => "kfkfk",
9 => "fk"
);
function GetMissingKey($Array,$Return_Type = false){
// Get the Maximum Key Value
$Max_Key = max(array_keys($Array));
// Treat this as the default array index, as all numerical arrays start at a 0 key set
$Counter = 0;
// A Blank array to be maniuplated
$Generated_Array = array();
// Generate a full array based on the maximum value and the array index, this will create a keyset from 0 to the highest value
while ($Counter < $Max_Key){
$Generated_Array[] = $Counter;
$Counter++;
}
// Discover the differences between the correctly formed array and the specified array keys
$Missing_Key = array_diff($Generated_Array,array_keys($Array));
// Work with the second parameter, as the settings.
if ($Return_Type === true){
// If set to true, we are expecting more than 1 free key within the array, so we will return the entire array
return $Missing_Key;
}elseif ($Return_Type === false){
// If set to false (or blank) we are expecting a single free key to be discovered & we will return it as an imploded array
return implode($Missing_Key);
}
}
print_R(GetMissingKey($Jumbled_Arr,true));
If true is passed through to this function, you will be returned with an array of missing keys.
If false is passed through, then you will be returned with a single integer (careful when if expecting more than one key to be returned).
$foo = array(1 => 'A', 5 => 'B', 2 => 'C', 3 => 'D', 6 => 'E', 0 => 'F');
$bar = array(1 => 'A', 4 => 'Z', 2 => 'L', 3 => 'N');
function firstFreeKey($array)
{
ksort($array);
for ($i = 0; $i <= count($array); $i++) {
if (!isset($array[$i])) {
return $i;
}
}
return count($array) + 1;
}
function firstFreeKeyNotZero($array)
{
$i = min(array_keys($array));
while (isset($array[$i])) {
$i++;
}
return $i;
}
echo firstFreeKey($foo); //returns 4
echo firstFreeKey($bar); //returns 0
echo firstFreeKeyNotZero($foo); //returns 4
echo firstFreeKeyNotZero($bar); //returns 5
Edit: Added case where not starting from 0, as requested by CodeAngry
To get all free keys:
$aArray = array(1 => 'A', 5 => 'B', 2 => 'C', 3 => 'D', 6 => 'E');
$iMaxKey = 7; //max key you will need
$aAllKeys = range(0, iMaxKey); //create array(0,1,2,3,4,5,6,7);
$aAllFreeKeys = array_diff_key($aAllKeys, $aArray); //will be: array(0,4,7);
and now if you need first free key:
$iKey = array_shift($aAllFreeKeys);

Categories