How to loop an array with strings as indexes in PHP - php

I had to make an array with as indexes A-Z (the alphabet). Each index had to have a value 0.
So i made this array:
$alfabet = array(
'A' => 0,
'B' => 0,
'C' => 0,
'D' => 0,
'E' => 0,
'F' => 0,
'G' => 0,
'H' => 0,
'I' => 0,
'J' => 0,
'K' => 0,
'L' => 0,
'M' => 0,
'N' => 0,
'O' => 0,
'P' => 0,
'Q' => 0,
'R' => 0,
'S' => 0,
'T' => 0,
'U' => 0,
'V' => 0,
'W' => 0,
'X' => 0,
'Y' => 0,
'Z' => 0
);
I also have got text from a file ($text = file_get_contents('tekst15.txt');)
I have putted the chars in that file to an array: $textChars = str_split ($text);
and sorted it from A-Z: sort($textChars);
What i want is that (with a for loop) when he finds an A in the textChars array, the value of the other array with index A, goes up by one (so like: $alfabet[A]++;
Can anyone help me with this loop? I have this atm:
for($i = 0; $i <= count($textChars); $i++){
while($textChars[$i] == $alfabet[A]){
$alfabet[A]++;
}
}
echo $alfabet[A];
Problem 1: i want to loop the alfabet array to, so now i only check for A but i want to check all indexes.
Problem2: this now returns 7 for each alphabet index i try so its totally wrong :)
I'm sorry about my english but thanks for your time.

Heard of the foreach loop?
foreach ($textChars as $index => $value) {
$alfabet[$value]++;
}

I assume that your $textChars array looks like
$textChars = array (
0 => 'A',
1 => 'A',
2 => 'B',
);
If so you can loop through it and use it's values to check if given index exists in $alfabet and then increment it.
foreach($textChars as $char){
if(isset($alfabet[$char])){
$alfabet[$char]++;
}
}

$fp = fopen('tekst15.txt', 'r');
if (!$fp) {
echo 'Could not open file tekst15.txt';
}
while (false !== ($char = fgetc($fp))) {
if(isset($alfabet[strtoupper($char)]))
{ $alfabet[strtoupper($char)] = $alfabet[strtoupper($char)]+1; }
}

The count_chars() function can give you that information immediately:
$stats = count_chars(file_get_contents('tekst15.txt'));
echo $stats['A']; // number of 'A' occurrences
echo $stats['O']; // number of 'O' occurrences
From your code:
while($textChars[$i] == $alfabet[A]){
$alfabet[A]++;
}
Made no sense at all; it compares each character from the text file to the value of $alfabet[A] which is 0 at first (not even a letter!).
The correct statement would be:
$alfabet[$textChars[$i]]++;

Related

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 use foreach() properly in PHP?

It is my first time coding in PHP. I am trying to return an array which contains of the amount of each type of cash
public function test($a){
$a = [];
$cash = array(
'20' => 0,
'30' => 0,
'40' => 0,
'50' => 0,
'60' => 0,
'70' => 0,
'80' => 0,
);
foreach($a as $k => $v) {
if (array_key_exists("$k",$cash) && $v!= null ) {
$cash[$k] += 1;
}
}
return $cash;
}
When I try testing the code I get the error: Invalid argument supplied for foreach()
the 1st argument for foreach() must be an array.
$a is not an array
Also note that you are trying to use $count, which was not previously defined as an array. Either that "$cash" assignment should be "$count" or vice-versa.
Try calling with test(array('20' => 0)); and you will not get the error. You are probably calling it with something that is not an array?
$cash[$key] += 1;
should be
$cash[$k] += 1;
I have included the code that I used for testing here:-
<?php
function test($a){
$cash = array(
'20' => 0,
'30' => 0,
'40' => 0,
'50' => 0,
'60' => 0,
'70' => 0,
'80' => 0,
);
foreach($a as $k => $v) {
if (array_key_exists("$k",$cash) && $v != NULL ) {
$cash[$k] += 1;
}
}
return $cash;
}
// code that I have added to test the function from the post question
$testArray = array(
'20' => 1,
'30' => 2,
'40' => 3,
'50' => 4,
'60' => 5,
'70' => 6,
'80' => 7,
);
$cash = test($testArray);
foreach($cash as $k => $v) {
echo("\n$k : $v");
}
?>
Results:-
20 : 1
30 : 1
40 : 1
50 : 1
60 : 1
70 : 1
80 : 1
Maybe you can try removing the comma at the end of your array.
change: '80' => 0,
to: '80' => 0

Roman Numeral to integer function [duplicate]

This question already has answers here:
How to convert a Roman numeral to integer in PHP?
(14 answers)
Closed 3 months ago.
basically i am trying to create a function that will turn a Roman numeral into a integer.
I have an array:
$roman_numerals=[
'M' => 1000,
'CM' => 900,
'D' => 500,
'CD' => 400,
'C' => 100,
'XC' => 90,
'L' => 50,
'XL' => 40,
'X' => 10,
'IX' => 9,
'V' => 5,
'IV' => 4,
'I' => 1
];
I'm fairly new to PHP so i'm still getting used to the way of think so please bear in mind i'm still learning :)
here is my function - or what i have so far:
//Array
function romanToInteger($key)
{
$roman_numerals=[
'M' => 1000,
'CM' => 900,
'D' => 500,
'CD' => 400,
'C' => 100,
'XC' => 90,
'L' => 50,
'XL' => 40,
'X' => 10,
'IX' => 9,
'V' => 5,
'IV' => 4,
'I' => 1
];
$roman = intval($key);
$result = 0;
foreach ($roman_numerals as $key => $value) {
while (strpos($roman, $key) === 0) {
$result += $value;
$roman = substr($roman, strlen($key));
}
}
var_dump($roman); //test
echo $result;
}
i have been at this for hours and would just like the see the light of it, any advice would be greatly appreciated.
when i run it in the command line with
echo romanToInteger('I');
i just get returned 0 and i think its something to do with my intval?
Sorry again for being a noob, help appreciated though or any pointers! :)
Yes it has something to do with the intval.
You're basically casting your roman input into an integer rendering it into 0.
Remove that:
function romanToInteger($key)
{
$romans = [
'M' => 1000,
'CM' => 900,
'D' => 500,
'CD' => 400,
'C' => 100,
'XC' => 90,
'L' => 50,
'XL' => 40,
'X' => 10,
'IX' => 9,
'V' => 5,
'IV' => 4,
'I' => 1,
];
$roman = $key;
$result = 0;
foreach ($romans as $key => $value) {
while (strpos($roman, $key) === 0) {
$result += $value;
$roman = substr($roman, strlen($key));
}
}
echo $result;
}
romanToInteger('IV');
Sample Output

PHP - More efficient method for sorting alphanumeric keys

NOTE: I edited the example and replaced all values with 1. The values do not matter, only the keys do. The previous values I had written led to a misunderstanding. Sorry.
NOTE: a/b blocks are always continuous. I'm adding this because it wasn't clear. If there is 3a/3b and 5a/5b there will always be 4a/4b and not only 4.
I have arrays that contain numbered keys with leading zeros. Sometimes, these numbered keys have two variations that I distinguish by using the suffixes a and b. The number of keys with or without variations is unknown, however there is never more than 2 digits; i.e. the highest numerical key is '09'.
The problem is that these array keys need to be sorted numerically, but when suffixes are present, those should take precedence. Using ksort() alone does not achieve this.
For example, ksort() gives me this:
$arr = array(
'01' => 1,
'02' => 1,
'03a' => 1,
'03b' => 1,
'04a' => 1,
'04b' => 1,
'05a' => 1,
'05b' => 1,
'06' => 1,
);
But, I need this:
$arr = array(
'01' => 1,
'02' => 1,
'03a' => 1,
'04a' => 1,
'05a' => 1,
'03b' => 1,
'04b' => 1,
'05b' => 1,
'06' => 1,
);
I use some fancy coding gymnastics to get what I want, but it isn't pretty. I'm wondering if there's a better, cleaner way?
Here is what I do.
1) I use ksort() which gives me the first of the two arrays above. (The one which isn't yet what I want.)
2) I create two arrays. One for the 'a' suffixes, the other for the 'b' suffixes.
$arr_a = array();
$arr_b = array();
foreach ($arr as $k => $v) {
if (substr($k, 2) == 'a') {
$arr_a[$k] = $v;
} else if (substr($k, 2) == 'b') {
$arr_b[$k] = $v;
}
}
3) I merge the two suffix arrays.
$arr_suffixes = array_merge($arr_a, $arr_b);
4) I slice up my original array so that I get the part before the suffixes, and the part after the suffixes.
$i = array_search(key($arr_suffixes), array_keys($arr));
$length = count($arr_suffixes);
$arr_before_suffixes = array_slice($arr, 0, $i);
$arr_after_suffixes = array_slice($arr, $i + $length);
5) Using array_merge, I recombine the sliced arrays to create the array I need.
$arr = array_merge($arr_before_suffixes, $arr_suffixes);
$arr = array_merge($arr, $arr_after_suffixes);
Finally, we have the correct $arr. Isn't there a better way to do this? It feels really ugly.
You have no formalized rule. I'll try to guess.
$arr = array(
'01' => 1,
'02' => 1,
'03a' => 1,
'03b' => 1,
'04a' => 1,
'04b' => 1,
'05a' => 1,
'05b' => 1,
'06' => 1,
);
uksort($arr, function($item1, $item2)
{
$last1 = substr($item1, -1);
$last2 = substr($item2, -1);
// one of the items is a number or last letters matches
if (is_numeric($last1) || is_numeric($last2) || $last1 == $last2)
// simple number comparison
return $item1 - $item2;
else
// natural order comparison
return $last1 > $last2 ? 1 : -1;
});
var_dump($arr);
natsort() function will helps you:
$arr = array(
'01' => 1,
'02' => 1,
'03a' => 1,
'03b' => 1,
'04a' => 1,
'04b' => 1,
'05a' => 1,
'05b' => 1,
'06' => 1,
);
$keys = array_keys($arr);
natsort($keys);
$result = array();
foreach ($keys as $key) {
$result[$key] = $arr[$key];
}
print_r($result); // Your expected result
$arr = array(
'01' => 1,
'02' => 2,
'03a' => 3,
'03b' => 6,
'04a' => 4,
'04b' => 7,
'05a' => 5,
'05b' => 8,
'06' => 9,
);
uksort(
$arr,
function($a, $b) {
sscanf($a, '%d%s', $an, $as);
sscanf($b, '%d%s', $bn, $bs);
if ($as === null || $bs === null || $as === $bs) {
return $an - $bn;
}
return strcmp($as, $bs);
}
);
var_dump($arr);

Decode a Crockford base32-string with an ISO-7064 Mod 37, 36-checksum

So I've been trying to wrap my head around this. I have a string encoded with Crockfords base32 algorithm, and a checksum based on ISO-7064 Mod 37, 36, which needs to be decoded in PHP.
String is "66QC" and checksum is "Q" which should be decoded to "203500. I've used this class to decode the string, but I'm still at a loss when it comes to the checksum. I can't seem to find any examples on this and feel lost. If someone has done anything similar or can point me the right direction it would be deeply appreciated.
I found a working example in VisualBasic and translated it to PHP. So if anybody's interested:
class ISO7064Decoder
{
public static $iso7064 = array(
'0' => 0,
'1' => 1,
'2' => 2,
'3' => 3,
'4' => 4,
'5' => 5,
'6' => 6,
'7' => 7,
'8' => 8,
'9' => 9,
'A' => 10,
'B' => 11,
'C' => 12,
'D' => 13,
'E' => 14,
'F' => 15,
'G' => 16,
'H' => 17,
'I' => 18,
'J' => 19,
'K' => 20,
'L' => 21,
'M' => 22,
'N' => 23,
'O' => 24,
'P' => 25,
'Q' => 26,
'R' => 27,
'S' => 28,
'T' => 29,
'U' => 30,
'V' => 31,
'W' => 32,
'X' => 33,
'Y' => 34,
'Z' => 35
);
public static function calculateCheckDigit(String $value)
{
$lngCheck = 36;
$lngLen = strlen($value);
for($lng = 0; $lng <= strlen($value)-1; $lng++)
{
$lngCheck = $lngCheck + self::charToNumber(substr($value, $lng, 1));
if($lngCheck > 36)
{
$lngCheck = $lngCheck - 36;
}
$lngCheck = $lngCheck * 2;
if($lngCheck >= 37)
{
$lngCheck = $lngCheck - 37;
}
}
$lngCheck = 37 - $lngCheck;
if($lngCheck == 36)
{
$lngCheck = 0;
}
return $lngCheck;
}
public static function charToNumber($value)
{
$value = strtoupper($value);
if(!array_key_exists($value, static::$iso7064))
{
return -1;
}
else
{
return static::$iso7064[$value];
}
}
}

Categories