I have an array that contains other arrays of US colleges broken down by the first letter of the alphabet. I've setup a test page so that you can see the array using print_r. That page is:
http://apps.richardmethod.com/Prehealth/Newpublic/test.php
In order to create that array, I used the following code:
$alphabetized = array();
foreach (range('A', 'Z') as $letter) {
// create new array based on letter
$alphabetized[$letter] = array();
// loop through results and add to array
foreach ( $users as $user ) {
$firstletter = substr($user->Schoolname, 0, 1);
if ( $letter == $firstletter ) {
array_unshift( $alphabetized[$letter], $user );
}
}
}
Now, I want to split the array so that a certain range of letters is in each array. For example,
arrayABCEFGH - would contain the schools that begin with the letters A, B, C, D, E, F, G, and H.
My question is, should I modify the code above so that I achieve this before I do one big array, OR should I do it after?
And here is the big question . . if so, how? :-)
Thanks in advance for any help. It's greatly appreciated.
First off, the code to generate the array can be made easier by only iteratating over $users:
$alphabetized = array();
// loop through results and add to array
foreach ($users as $user) {
$firstletter = strtoupper($user->Schoolname[0]);
$alphabetized[$firstletter][] = $user;
}
// sort by first letter (optional)
ksort($alphabetized);
To retrieve the first 8 entries you could use array_slice:
array_slice($alphabetized, 0, 8);
Assuming that all first letters are actually used and you used ksort() on the full array that also gives you from A - H. Otherwise you have to use array_intersect_key() and the flipped range of letters you wish to query on.
array_intersect_key($alphabetized, array_flip(range('A', 'H')));
If you don't need a full copy of the array, then you should encapsulate the above code in a function that has an array as its argument ($letterRange), which will hold the specific array identifiers (letters) to be in the final array.
Then you would need to encapsulate the code within the foreach using an if block:
if (in_array($letter, $letterRange)) { ... }
This would result in an array only containing the letter arrays for the specified letters in $letterRange.
You could write a simple function that takes an array, and an array of keys to extract from that array, and returns an array containing just those keys and their values. A sort of array_slice for non-numeric keys:
function values_at($array, $keys) {
return array_intersect_key($array, array_flip($keys));
}
Which you can then call like this to get what you want out of your alphabetized list:
$arrayABCDEFGH = values_at($alphabetized, range('A','H'));
Related
The following is the code
<?php
$id ="202883-202882-202884-0";
$str = implode('-',array_unique(explode('-', $id)));
echo $str;
?>
The result is
202883-202882-202884-0
for $id ="202883-202882-202882-0";, result is 202883-202882-0
I would like to replace the duplicate value with zero, so that the result should be like 202883-202882-0-0, not just remove it.
and for $id ="202883-0-0-0";, result should be 202883-0-0-0. zero should not be replaced, repeating zeros are allowed.
How can I archive that?
More info:
I want to replace every duplicate numbers. Because this is for a product comparison website. There will be only maximum 4 numbers. each will be either a 6 digit number or single digit zero. all zero means no product was selected. one 6 digit number and 3 zero means, one product selected and 3 blank.
Each 6 digit number will collect data from database, I dont want to allow users to enter same number multiple times (will happen only if the number is add with the URL manually.).
Update: I understand that my question was not clear, may be my English is poor.
Here is more explanation, this function is for a smartphone comparison website.
The URL format is sitename.com/compare.html?id=202883-202882-202889-202888.
All three numbers are different smartphones(their database product ID).
I dont want to let users to type in the same product ID like id=202883-202882-202882-202888. It will not display two 202882 results in the website, but it will cause some small issues. The URL will be same without change, but the internal PHP code should consider it as id=202883-202882-202888-0.
The duplicates should be replaced as zero and added to the end.
There will be only 4 numbers separated by "-".
The following examples might clear the cloud!
if pid=202883-202882-202889-202888 the result should be 202883-202882-202889-202888
if pid=202883-202883-202883-202888 the result should be 202888-0-0-0
if pid=202883-202882-202883-202888 the result should be 202883-202882-202888-0
if pid=202882-202882-202882-202882 the result should be 202882-0-0-0
I want to allow only either 6 digit numbers or single digit zero through the string.
if pid=rgfsdg-fgsdfr4354-202883-0 the result should be 202883-0-0-0
if pid=fasdfasd-asdfads-adsfds-dasfad the result should be 0-0-0-0
if pid=4354-45882-445202882-202882 the result should be 202882-0-0-0
It is too complicated for me create, I know there are bright minds out there who can do it much more efficiently than I can.
You can do a array_unique (preserves key), then fill the gaps with 0. Sort by key and you are done :)
+ on arrays will unify the arrays but prioritizes the one on the left.
Code
$input = "0-1-1-3-1-1-3-5-0";
$array = explode('-', $input);
$result = array_unique($array) + array_fill(0, count($array), 0);
ksort($result);
var_dump(implode('-',$result));
Code (v2 - suggested by mickmackusa) - shorter and easier to understand
Fill an array of the size of the input array. And replace by leftover values from array_unique. No ksort needed. 0s will be replaced at the preserved keys of array_unique.
$input = "0-1-1-3-1-1-3-5-0";
$array = explode('-', $input);
$result = array_replace(array_fill(0, count($array), 0), array_unique($array));
var_export($result);
Working example.
Output
string(17) "0-1-0-3-0-0-0-5-0"
Working example.
references
ksort - sort by key
array_fill - generate an array filled with 0 of a certain length
This is another way to do it.
$id = "202883-202882-202882-0-234567-2-2-45435";
From the String you explode the string into an array based on the delimiter which in this case is '-'/
$id_array = explode('-', $id);
Then we can loop through the array and for every unique entry we find, we can store it in another array. Thus we are building an array as we search through the array.
$id_array_temp = [];
// Loop through the array
foreach ($id_array as $value) {
if ( in_array($value, $id_array_temp)) {
// If the entry exists, replace it with a 0
$id_array_temp[] = 0;
} else {
// If the entry does not exist, save the value so we can inspect it on the next loop.
$id_array_temp[] = $value;
}
}
At the end of this operation we will have an array of unique values with any duplicates replaced with a 0.
To recreate the string, we can use implode...
$str = implode('-', $id_array_temp);
echo $str;
Refactoring this, using a ternary to replace the If,else...
$id_array = explode('-', $id);
$id_array_temp = [];
foreach ($id_array as $value) {
$id_array_temp[] = in_array($value, $id_array_temp) ? 0 : $value;
}
$str = implode('-', $id_array_temp);
echo $str;
Output is
202883-202882-0-0-234567-2-0-45435
This appears to be a classic XY Problem.
The essential actions only need to be:
Separate the substrings in the hyphen delimited string.
Validate that the characters in each substring are in the correct format AND are unique to the set.
Only take meaningful action on qualifying value.
You see, there is no benefit to replacing/sanitizing anything when you only really need to validate the input data. Adding zeros to your input just creates more work later.
In short, you should use a direct approach similar to this flow:
if (!empty($_GET['id'])) {
$ids = array_unique(explode('-', $_GET['id']));
foreach ($ids as $id) {
if (ctype_digit($id) && strlen($id) === 6) {
// or: if (preg_match('~^\d{6}$~', $id)) {
takeYourNecessaryAction($id);
}
}
}
I am a noob attempting to solve a program for a word search app I am doing. My goal is to take a string and compare how many times each letter of that string appears in another string. Then put that information into an array of key value pairs, where the key is each letter of the first string and the value is the number of times. Then order it with ar(sort) and finally echo out the value of the letter that appears the most (so the key with the highest value).
So it would be something like array('t' => 4, 'k' => '9', 'n' => 55), echo the value of 'n'. Thank you.
This is what I have so far that is incomplete.
<?php
$i = array();
$testString= "endlessstringofletters";
$testStringArray = str_split($testString);
$longerTestString= "alphabetalphabbebeetalp
habetalphabetbealphhabeabetalphabetalphabetalphbebe
abetalphabetalphabetbetabetalphabebetalphabetalphab
etalphtalptalphabetalphabetalbephabetalphabetbetetalphabet";
foreach ($testStringArray AS $test) {
$value = substr_count($longerTestString, $testStringArray );
/* Instead of the results of this echo, I want each $value to be matched with each member of the $testStringArray and stored in an array. */
echo $test. $value;
}
/* I tried something like this outside of the foreach and it didn't work as intended */
$i = array_combine($testStringArray , $value);
print_r($i);
If I understand correctly what you are after, then it's as simple as this:
<?php
$shorterString= "abc";
$longerString= "abccbaabaaacccb";
// Split the short sring into an array of its charachters
$stringCharachters = str_split($shorterString);
// Array to hold the results
$resultsArray = array();
// Loop through every charachter and get their number of occurences
foreach ($stringCharachters as $charachter) {
$resultsArray[$charachter] = substr_count($longerString,$charachter);
}
print_r($resultsArray);
This is my array
$input = array("ASTY","PLO","KNGO","c","LOP","OPL","HONGO","TSAY");
here,
ASTY,TSAY = contains same letters. I need to keep first one.
PLO,LOP,OPL= contains same letters. I need to keep first one.
So, my desired output array
$output = array("ASTY","PLO","KNGO","c","HONGO");
Is there any builtin function to do this?
array_unique works fine for non-rearranged word.
To compare whether any two values are equal in this scenario, you would simply order the letters and compare the ordered value. To deduplicate the array, use the fact that arrays keys are unique:
$unique = [];
foreach ($input as $word) {
$key = str_split($word);
sort($key);
$unique[join($key)] = $word;
}
// optionally:
$unique = array_values($unique);
I have officially hit a wall and I cannot figure out the solution to this issue. Any help would be much appreciated! I have tried array_intersect() but it just keeps running against the first array in the function, that wont work.
I have an infinite amounts of arrays (I'll show 4 for demonstration purposes), for example:
// 1.
array(1,2,3,4,5);
// 2.
array(1,3,5);
// 3.
array(1,3,4,5);
// 4.
array(1,3,5,6,7,8,9);
I need to figure out how to search all the arrays and find only the numbers that exist in all 4 arrays. In this example I need to only pull out the values from the arrays - 1, 3 & 5.
PS: In all reality, it would be best if the function could search against a multi dimensional array and extract only the numbers that match in all the arrays within the array.
Thanks so much for your help!
Fun question! This worked:
function arrayCommonFind($multiArray) {
$result = $multiArray[0];
$count = count($multiArray);
for($i=1; $i<$count; $i++) {
foreach($result as $key => $val) {
if (!in_array($val, $multiArray[$i])) {
unset($result[$key]);
}
}
}
return $result;
}
Note that you can just use $multiArray[0] (or any sub-array) as a baseline and check all the others against that since any values that will be in the final result must necessarily be in all individual subarrays.
How about this?
Find the numbers that exist in both array 1 and 2. Then compare those results with array 3 to find the common numbers again. Keep going as long as you want.
Is this what you are getting at?
If it's in a multidimensional array you could
$multiDimensional = array(/* Your arrays*/);
$found = array_pop($multiDimensional);
foreach($multiDimensional as $subArray)
{
foreach($found as $key=>$element)
{
if(!in_array($element, $subArray)
{
unset($found[$key]);
}
}
}
Per your comment on my other question here is a better solution:
<?php
// 1. merge the arrays
$merged_arrays = array_merge( $arr1, $arr2, $arr3, $arr4, ...);
// 2. count the values
$merged_count = array_count_values( $merged_arrays );
// 3. sort the result for elements that only matched once
for( $merged_count as $key => $value ){
if ($value == 1) {
// 4. unset the values that didn't intersect
unset($merged_count($key));
}
}
// 5. print the resulting array
print_r( $merged_count );
Performing iterated in_array() calls followed by unset() is excessive handling and it overlooks the magic of array_intersect() which really should be the hero of any solid solution for this case.
Here is a lean iterative function:
Code: (Demo)
function array_intersect_multi($arrays){ // iterative method
while(sizeof($arrays)>1){
$arrays[1]=array_intersect($arrays[0],$arrays[1]); // find common values from first and second subarray, store as (overwrite) second subarray
array_shift($arrays); // discard first subarray (reindex $arrays)
}
return implode(', ',$arrays[0]);
}
echo array_intersect_multi([[1,2,3,4,5],[1,3,5],[1,3,4,5],[1,3,5,6,7,8,9]]);
// output: 1, 3, 5
This assumes you will package the individual arrays into an indexed array of arrays.
I also considered a recursive function, but recursion is slower and uses more memory.
function array_intersect_multi($arrays){ // recursive method
if(sizeof($arrays)>1){
$arrays[1]=array_intersect($arrays[0],$arrays[1]); // find common values from first and second subarray, store as (overwrite) second subarray
array_shift($arrays); // discard first subarray (reindex $arrays)
return array_intersect_multi($arrays); // recurse
}
return implode(', ',$arrays[0]);
}
Furthermore, if you are happy to flatten your arrays into one with array_merge() and declare the number of individual arrays being processed, you can use this:
(fastest method)
Code: (Demo)
function flattened_array_intersect($array,$total_arrays){
return implode(', ',array_keys(array_intersect(array_count_values($array),[$total_arrays])));
}
echo flattened_array_intersect(array_merge([1,2,3,4,5],[1,3,5],[1,3,4,5],[1,3,5,6,7,8,9]),4);
or replace array_intersect() with array_filter() (slightly slower and more verbose):
function flattened_array_intersect($array,$total_arrays){
return implode(', ',array_keys(array_filter(array_count_values($array),function($v)use($total_arrays){return $v==$total_arrays;})));
}
echo flattened_array_intersect(array_merge([1,2,3,4,5],[1,3,5],[1,3,4,5],[1,3,5,6,7,8,9]),4);
What i am trying to do is really but i am going into a lot of detail to make sure it is easily understandable.
I have a array that has a few strings in it. I then have another that has few other short strings in it usually one or two words.
I need it so that if my app finds one of the string words in the second array, in one of the first arrays string it will proceed to the next action.
So for example if one of the strings in the first array is "This is PHP Code" and then one of the strings in the second is "PHP" Then it finds a match it proceeds to the next action. I can do this using this code:
for ( $i = 0; $i < count($Array); $i++) {
$Arrays = strpos($Array[$i],$SecondArray[$i]);
if ($Arrays === false) {
echo 'Not Found Array String';
}
else {
echo 'Found Array String';
However this only compares the First Array object at the current index in the loop with the Second Array objects current index in the loop.
I need it to compare all the values in the array, so that it searches every value in the first array for the First Value in the second array, then every value in the First array for the Second value in the second array and so on.
I think i have to do two loops? I tried this but had problems with the array only returning the first value.
If anyone could help it would be appreciated!
Ill mark the correct answer and + 1 any helpful comments!
Thanks!
Maybe the following is a solution:
// loop through array1
foreach($array1 as $line) {
// check if the word is found
$word_found = false;
// explode on every word
$words = explode(" ", $line);
// loop through every word
foreach($words as $word) {
if(in_array($word, $array2)) {
$word_found = true;
break;
}
}
// if the word is found do something
if($word_found) {
echo "There is a match found.";
} else {
echo "No match found."
}
}
Should give you the result you want. I'm absolute sure there is a more efficient way to do this.. but thats for you 2 find out i quess.. good luck
You can first normalize your data and then use PHP's build in array functions to get the intersection between two arrays.
First of all convert each array with those multiple string with multiple words in there into an array only containing all words.
A helpful function to get all words from a string can be str_word_count.
Then compare those two "all words" arrays with each other using array_intersect.
Something like this:
$words1 = array_unique(str_word_count(implode(' ', $Array), 1));
$words2 = array_unique(str_word_count(implode(' ', $SecondArray), 1));
$intersection = array_intersect($words1, $words2);
if(count($intersection))
{
# there is a match!
}
function findUnit($packaging_units, $packaging)
{
foreach ($packaging_units as $packaging_unit) {
if (str_contains(strtoupper($packaging[3]), $packaging_unit)) {
return $packaging_unit;
}
}
}
Here First parameter is array and second one is variable to find