Merging numbered lists in PHP - php

I have a set of items with numbers already assigned to them and am trying to fill in the gaps that the person before me left in the spreadsheet. I figured I could write a php script to do this for me yet it's placing the assigned numbers in weird spots.
Here's an example:
I have an associative array of numbers / names
[0] => 3502 "Scallops, Bay" [1] => 3503 "Oysters, Chesepeake" [2] => 3504 "Clams, Cherry Stone"
The script to order these is:
$d = file("list.txt");
$j=0;
for ($i=2000;$i<8000;$i++) { //I want the codes to begin at the 2000 and end at 8000
if (strpos($d[$j], $i) !== false) {
echo $d[$j]."<br/>";
$j++;
} else {
echo $i."<br/>";
}
}
But here's what I'm getting:
2000-2056 print out fine, because they don't match [0] of $d, but then on 2057 it prints
2056
3502 "Scallops, Bay"
3503 "Oysters, Chesepeake"
2059
2060
3504 "Clams, Chery Stone"
Then goes to print on until 2080 where it prints [3] of $d.
I'm really confused. I don't see 2057 anywhere in "3502 'Scallops, Bay'"
Should I be trying a different approach?

The second argument to strpos() can be an integer or a string; if it's an integer, it's ordinal value is used to search. From the manual:
If needle is not a string, it is converted to an integer and applied as the ordinal value of a character.
You should cast the index to a string first:
if (strpos($d[$j], "$i") !== false) {
Btw, it would be better to check whether the line starts with $i and whether $d[$j] is still a valid entry:
if (isset($d[$j]) && strpos($d[$j], "$i\t") === 0) {

It's because of the order. If the script reache lets say 5000 with index of 1, it won't find 3000 with index 2.
My solution:
$A = array('3000 abc street', '2000 something', '5000 somthing other');
function ScanFor($Number, &$A) //& is realy important
{
foreach($A as $I => $V)
if(strpos($Number, $V) === 0) // so it starts with it
{
unset($A[$I]); //We don't want it anymore
list(, $Name) = explode(' ', $V, 1); //After Number there is always space, so we split it to 2 parts
return $Name;
}
return '';
}
for($I = 2000; $I < 10000; $I++)
{
printf("%d", $I);
if($Name = ScanFor($I, $A))
{
printf("\t%s", $Name)
}
printf("<br>\n");
}

Try working with the file like csv and use SplMinHeap to sort
Example:
// Where to store Result
$store = new SortedValue();
// Read File
$fp = fopen("list.txt", "r");
// Read each file content
while(($data = fgetcsv($fp, 1000, " ")) !== FALSE) {
// Filter Empty space
$data = array_filter($data);
// Your Filter
if ($data[0] > 2000 && $data[0] < 8000) {
$store->insert($data);
}
}
// Print_r all result
print_r(iterator_to_array($store));
Class Used
class SortedValue extends SplMinHeap {
function compare($a, $b) {
return $b[0] - $a[0];
}
}

Related

PHP, regex and multi-level dashes and grouping together according to string occurrence

I have a string which looks like this:
15-02-01-0000
15-02-02-0000
15-02-03-0000
15-02-04-0000
15-02-05-0000
15-02-10-0000
15-02-10-9100
15-02-10-9101
15-15-81-0000
15-15-81-0024
So the expected output would be:
All account grouping separated by "-" dashes for example: 15-02-01-0000 there is 3 grouping
start with 15
start with 15-02
start with 15-02-01
So the expected output would be:
First it will show
15 --> All account start with "15"
15-02 --> All account start with "15-02"
15-02-01 -- All accounts start with "15-02-01"
15-02-01-0000
15-02-02 -- All accounts start with 15-02-02
15-02-02-0000
15-02-03 -- onwards like above
15-02-03-0000
15-02-04
15-02-04-0000
15-02-05
15-02-05-0000
15-02-10
15-02-10-0000
15-02-10-9100
15-02-10-9101
15-15
15-15-81
15-15-81-0000
15-15-81-0024
I tried to use substr:
$res = substr("15-15-81-0024",3,2);
if ($res == "15") {
} else if ($res < 10 && $res != 00) {
} else {
}
But not working to put grouping.
Could you please suggest any good way?
You can break each data by - and build the array in as much as needed. Notice the use of & in the code as using reference to result array.
Example:
$str = "15-02-01-0000,15-02-02-0000,15-02-03-0000,15-02-04-0000,15-02-05-0000,15-02-10-0000,15-02-10-9100,15-02-10-9101,15-15-81-0000,15-15-81-0024";
$arr = explode(",", $str);
$res = [];
foreach($arr as $e) { // for each line in your data
$a = explode("-", $e); //break to prefix
$current = &$res;
while(count($a) > 1) { // create the array to that specific place if needed
$key = array_shift($a); // take the first key
if (!isset($current[$key])) // if the path not exist yet create empty array
$current[$key] = array();
$current = &$current[$key];
}
$current[] = $e; // found the right path so add the element
}
The full result will be in $res.
I'd probably do something along the lines of:
Could be more efficient if more time was spent on it.
<?php
$random = '15-02-01-0000
15-02-02-0000
15-02-03-0000
15-02-04-0000
15-02-05-0000
15-02-10-0000
15-02-10-9100
15-02-10-9101
15-15-81-0000
15-15-81-0024';
$lines = explode(PHP_EOL, $random);
$accounts = return_count($lines);
var_dump($accounts);
function return_count($lines){
$count_accounts = array();
$possibilties = array();
if(is_array($lines) && !empty($lines)){
foreach($lines as $val){
$line = explode('-', $val);
array_push($possibilties, $line[0], $line[0] . '-' . $line[1], $line[0] . '-' . $line[1] . '-' . $line[2]);
}
foreach($possibilties as $pos){
if(!isset($count_accounts[$pos])){ $count_accounts[$pos] = 0;}
if(search_array($pos, $lines)){
$count_accounts[$pos]++;
}
}
}
return $count_accounts;
}
function search_array($string, $array){
$found = 0;
if(is_array($array) && !empty($array)){
foreach($array as $val){
if (strpos($val, $string) !== false) {
$found = 1;
}
}
if($found == 1){
return true;
}else{
return false;
}
}else{
return false;
}
}
?>
Which returns:
array (size=10)
15 => int 10
'15-02' => int 8
'15-02-01' => int 1
'15-02-02' => int 1
'15-02-03' => int 1
'15-02-04' => int 1
'15-02-05' => int 1
'15-02-10' => int 3
'15-15' => int 2
'15-15-81' => int 2

How to continuously push user input data into $_SESSION array and then retrieve it?

I am trying to get my head around the way PHP sessions work. I am simply trying a hangman game where the first player inputs a secret word, a second player then starts to guess one letter at a time.
Let's says that the secret word is cat, player two tries, c then a then s. I would like the final output to be c a _.
<?php
session_start();
global $word;
global $guess;
global $hangman;
if (isset($_POST['player1'], $_POST['word'])) {
$_SESSION['word'] = $_POST['word'];
$word = $_SESSION['word'];
}
if (isset($_POST['player2'], $_POST['guess'])) {
$_SESSION['guess'] = $_POST['guess'];
$guess = $_SESSION['guess'];
}
$counter = 0;
$word = strtolower($_SESSION['word']);
$guess = strtolower($_SESSION['guess']);
echo $word . "<br>";
$found = [];
$counter = 0;
for ($i = 0; $i < strlen($word); $i++) {
if ($counter < strlen($word)) {
if (strpos($word[$i], $guess) !== false) {
$found[] = $guess;
$counter++;
} else {
$found[] = " _ ";
}
}
}
print_r($found);
Instead of printing out all the contents the found array, I am only getting one single letter to print every time. However, I would like to see the full concatenated string as I've mentioned above.
Here is what the output looks like:
How to continuously push user input data into $_SESSION array and then retrieve it?
An easy way to do that is by binding a variable with an element in the $_SESSION array.
This is a useful trick that you won't find in the manual.
A simple example:
$foo =& $_SESSION['foo'];
That assignment will bind $foo and $_SESSION['foo'] to the same value,
so every update to $foo is also an update to $_SESSION['foo'].
Here is an example usage in the style of your hangman game:
<?php
session_start();
$word =& $_SESSION['word']; //bind $word with $_SESSION['word']
$found =& $_SESSION['found']; //bind $found with $_SESSION['found']
if (isset($_REQUEST['word'])) {
$word = str_split($_REQUEST['word']);
$found = array_fill(0, count($word), '_');
}
if (isset($_REQUEST['guess'], $word, $found)) {
$guess = array_fill(0, count($word), $_REQUEST['guess']);
$found = array_replace($found, array_intersect($word, $guess));
}
echo join(' ', $found);
With the binding, the values of $word and $found will be saved as a part of the session data,
without the need to do $_SESSION['word'] = $word; and $_SESSION['found'] = $found; anywhere in the script.
Note that I use $_REQUEST instead of $_POST to make it easier to test with a browser.
Modify as desired.
Make the $found as a string variable.Instead of pushing in $found[] ,concatenate $guess Like $found .= $guess;
You should save what was already found between requests, since now you are just searching the $_SESSION['word'] for the char in the last request.
if ( isset($_POST['player1']) && !empty($_POST['word']) ) {
$_SESSION['word'] = str_split( $_POST['word'] );
// ceate empty array for storing the already found chars
$_SESSION['found'] = str_split( str_repeat( " ", strlen($_POST['word']) ) );
}
if ( isset($_POST['player2']) && !empty($_POST['guess']) ) {
array_walk( $_SESSION['word'], function( $v, $k ) {
if ( $v == $_POST['guess'] )
$_SESSION['found'][$k] = $v;
});
}
if ( $_SESSION['word'] == $_SESSION['found'] )
echo 'Game Over';
print_r( $_SESSION['found'] );
You are overwriting your $_SESSION['guess'] with:
$_SESSION['guess'] = $_POST['guess'];
on every submission.
I would recommend that you store your posted guesses as a subarray of letters like:
$_SESSION['guesses'][] = $_POST['guess'];
Then you will never overwrite earlier guesses.
This will mean you will have a session array with this type of structure:
$_SESSION=[
'player1' => 'me',
'word' => 'cat',
'player2' => 'myself',
'guesses' => ['a','c']
];
From here, you can call str_split() on $_SESSION['word'] and check for found/remaining letters using $_SESSION['guesses'] and array comparison functions.
Here are some untested portions of code that may help you along...
session_start();
if (!isset($_SESSION['player1'], $_SESSION['word'])) { // no stored player1 or word
if (!isset($_POST['player1'], $_POST['word'])) { // no posted player1 or word
// show form with player1 and word fields
} else {
$_SESSION=['player1'=>$_POST['player1'],'word'=>strtolower($_POST['word'])]; // store player1 and word
}
} elseif (!isset($_SESSION['player2'], $_SESSION['guesses'])){ // no stored player2 or guesses
if (!isset($_POST['player2'], $_POST['guess'])) { // no posted player2 or guess
// show form with player2 and first guess
} else {
$_SESSION['player2'] = $_POST['player1']; // store player2
$_SESSION['guesses'] = [strtolower($_POST['guess'])]; // store guessed character as first element of subarray
}
} elseif (isset($_POST['guess'])) {
$_SESSION['guesses'][] = strtolower($_POST['guess']); // store guessed character
}
And further down script here are some pieces...
$secret_letters=array_unique(str_split($_SESSION['word'])); // unique secret word letters
$found_letters=array_intersect($secret_letters,$_SESSION['guesses']); // unique found letters
if($secret_letters===$found_letters){
// player2 guessed all of the secret letters, set off fireworks
}else{
// some useful bits of code...
$not_yet_found=array_diff($secret_letters,$_SESSION['guesses']);
$underscored=str_replace($not_yet_found,'_',$_SESSION['word']); // e.g. 'ca_'
$space_out=implode(' ',str_split($underscored)); // e.g. 'c a _'
$wrong_letters=array_diff($_SESSION['guesses'],$secret_letters); // letters guessed but not part of secret word
// when count($wrong_letters) reaches your designated limit, then the guesser loses
$avaliable_letters=array_diff(range('a','z'),$_SESSION['guesses']);
$select="<select name=\"guess\"><option>".implode('</option><option>',$available_letters)."</option></select>";
}
I should also note, there are many ways to tackle this project. You should have a look at count_chars(), it has multiple modes which you should research and consider.
There will be regex methods that may be helpful, but I won't open up that can for you.
I see your problem now. you didn't save or hold the previous guess because your found[] array variable is always empty.
try to save the found result in a session
and change this following line of code:
for ($i = 0; $i < strlen($word); $i++) {
if ($counter < strlen($word)) {
if (strpos($word[$i], $guess) !== false) {
$found[] = $guess;
$counter++;
} else {
$found[] = " _ ";
}
}
}
TO:
$counterWord = strlen($word);
for ($i = 0; $i < $counterWord ; $i++) {
if (strpos($word[$i], $guess) !== false) {
$found[$i] = $guess; // $i indicates what index should be changed
} else {
if(!isset($found[$i])){
$found[$i] = "_";
}
}
$_SESSION['found'] = $found;
and add this line of code under the declaring of your $found array variable:
$found = [];
if(isset($_SESSION['found'])){ //checker if the variable is set and not empty
$found = $_SESSION['found']; // getting the value of found and store it in found variable
}

Form a new string with data from an array PHP

I would need to reduce the quantity of these numbers and present them in a more concise way, instead of presenting several lines of numbers with the same "prefix" or "root". For example:
If I have an array like this, with several strings of numbers (obs: only numbers and the array is already sorted):
$array = array(
"12345647",
"12345648",
"12345649",
"12345657",
"12345658",
"12345659",
);
The string: 123456 is the same in all elements of the array, so it would be the root or the prefix of the number. According to the above array I would get a result like this:
//The numbers in brackets represent the sequence of the following numbers,
//instead of showing the rows, I present all the above numbers in just one row:
$stringFormed = "123456[4-5][7-9]";
Another example:
$array2 = array(
"1234",
"1235",
"1236",
"1247",
"2310",
"2311",
);
From the second array, I should get a result like this:
$stringFormed1 = "123[4-7]";
$stringFormed2 = "1247";
$stringFormed3 = "231[0-1]";
Any idea?
$array = array(
"12345647",
"12345648",
"12345649",
"12345657",
"12345658",
"12345659",
);
//find common string positions for all elements
$res = array();
foreach($array as $arr){
for($i=0;$i<strlen($arr);$i++){
$res[$i][$arr[$i]] = $arr[$i];
}
}
//make final string
foreach($res as $pos){
if(count($pos)==1)
$str .= implode('',$pos);
else{
//u may need to sort these values if you want them in order
$end = end($pos);
$first = reset($pos);
$str .="[$first-$end]";
}
}
echo $str; // "123456[4-5][7-9]";
Well, as I understand you want the final string with unique characters. (i'm not sure if you want it ordered)
So, first implode to create the string
$stringFormed = implode("", $array);
Then we get the unique chars :
$stringFormed=implode("",array_unique(str_split($stringFormed)));
OUTPUT: 123456789
That as a solution for first example but i didn't thought there could be several roots.
By the way i'm not sure it's well coded...
<?php
function longest_common_substring($words)
{
$words = array_map('strtolower', array_map('trim', $words));
$sort_by_strlen = create_function('$a, $b', 'if (strlen($a) == strlen($b)) { return strcmp($a, $b); } return (strlen($a) < strlen($b)) ? -1 : 1;');
usort($words, $sort_by_strlen);
// We have to assume that each string has something in common with the first
// string (post sort), we just need to figure out what the longest common
// string is. If any string DOES NOT have something in common with the first
// string, return false.
$longest_common_substring = array();
$shortest_string = str_split(array_shift($words));
while (sizeof($shortest_string)) {
array_unshift($longest_common_substring, '');
foreach ($shortest_string as $ci => $char) {
foreach ($words as $wi => $word) {
if (!strstr($word, $longest_common_substring[0] . $char)) {
// No match
break 2;
} // if
} // foreach
// we found the current char in each word, so add it to the first longest_common_substring element,
// then start checking again using the next char as well
$longest_common_substring[0].= $char;
} // foreach
// We've finished looping through the entire shortest_string.
// Remove the first char and start all over. Do this until there are no more
// chars to search on.
array_shift($shortest_string);
}
// If we made it here then we've run through everything
usort($longest_common_substring, $sort_by_strlen);
return array_pop($longest_common_substring);
}
$array = array(
"12345647",
"12345648",
"12345649",
"12345657",
"12345658",
"12345659",
);
$result= longest_common_substring($array);
for ($i = strlen($result); $i < strlen($array[0]); $i++) {
$min=intval($array[0][$i]);
$max=$min;
foreach ($array as $string) {
$val = intval($string[$i]);
if($val<$min)
$min=$val;
elseif($val>$max)
$max=$val;
}
$result.='['.$min.'-'.$max.']';
}
echo $result;
?>

php remove value from array

Hi I need help in removing values from an array using a recursive function
$array = [0] => testing,testing1
[1] => testing,testing1,testing2
[2] => testing,testing1,testing2,testing3
[3] => testing,testing1,testing2,testing3,tesing4
[4] => testing,testing1,testing2,testing3,tesing4
[5] => testing,testing1,testing2,testing3,tesing4
[6] => testing,testing1,testing2,testing3,tesing4
[7] => testing,testing1,testing2,testing3,tesing4
I need to check the array count, ie if count(array[0]) == count(array[1]),then reutrn array
else unset(array[value]);
From the above array I have to remove array[0],[1],[2] and return rest of the array values.
I've tried the below code
$idx =10;
$separtor =',';
function array_delete($idx, $array,$separtor) {
$finalvalue = array();
for ($i = 0; $i < $idx; $i++) {
$values = explode($separtor, $array[$i]);
$valuesnext = explode($separtor, $array[$i+1]);
if(count($values) != count($valuesnext) )
{
unset($array[$i]);
// reset($array);
// array_delete($idx, $array,$separtor);
if (is_array($array)) $array = array_delete($idx, $array,$separtor);
$finalvalue = $array;
}else
{
}
//echo $i;
}
return $finalvalue;
//(is_array($array)) ? array_values($array) : null;
//array_delete($idx, $array,$separtor);
}
I'm getting Notice: Undefined offset: 0 when trying calling recursive, going to infinite loop
Do you want to keep the sub-arrays that have the most items? Your descriptions appear to say this.
If so, something like the following would suffice.
// Get maximum number of items in the arrays
$max_count = max(array_map('count', $array));
// Keep only those arrays having $max_count items
$filtered = array_filter($array, function ($a) use ($max_count) {
return count($a) === $max_count;
});
Aside: if you need the filtered array to have zero-based keys, call array_values() on it.
See an example running online.
If I understand correctly, you want to filter the array such that any value in the final array is of the same length as the last element in the source array. In order to avoid mutating an array while iterating over it, this technique builds a fresh array with the elements that match your criteria.
$matchLength = count($mainArray[count($mainArray) - 1]);
$resultArray = array();
for($i = 0; $i < count($mainArray); $i++) {
if(count($mainArray[$i]) == $matchLength) {
$resultArray[] = $mainArray[$i];
}
}
If you happen to be using PHP 5.3 or greater, you can do this quicker with closures and array_filter:
$matchLength = count($mainArray[count($mainArray) - 1]);
$resultArray = array_filter($mainArray, function($element){return count($element) == $matchLength});
Double check the code, I haven't been writing PHP lately, so this is just an idea.
According to the description you gave, it could be just made (check the count of the current and the provious one, if they don't match, remove the previous one).
Example/Demo:
unset($prevKey);
$count = array();
foreach (array_keys($array) as $key) {
$count[$key] = count($array[$key]);
if (isset($prevKey) && $count[$prevKey] !== $count[$key]) {
unset($array[$prevKey]);
}
$prevKey = $key;
}
If you need to re-iterate to take removals into account, a little goto can do the job Demo:
start:
######
unset($prevKey);
$count = array();
foreach (array_keys($array) as $key) {
$count[$key] = count($array[$key]);
if (isset($prevKey) && $count[$prevKey] !== $count[$key]) {
unset($array[$prevKey]);
goto start;
###########
}
$prevKey = $key;
}

Sorting data and print out in alphabetic order

I got an array which contains some data like this:
$arrs = Array("ABC_efg", "##zzAG", "#$abc", "ABC_abc")
I was trying to print the data out in this way (Printing in alphabetic order):
[String begins with character A]
ABC_abc
ABC_efg
[String begins with character other than A to Z]
#$abc
##zzAG
I'm going to assume you mean strings starting with a letter should appear before all other strings and all strings should otherwise be sorted in the standard order.
You use usort() and define a custom function for the ordering and ctype_alpha() to determine if something is a letter or not.
$arrs = Array("ABC_efg", "##zzAG", "#$abc", "ABC_abc");
usort($arrs, 'order_alpha_first');
function order_alpha_first($a, $b) {
$lenA = strlen($a);
$lenB = strlen($b);
$len = min($lenA, $lenB);
$i = 0;
while ($a[$i] == $b[$i] && $i < $len) {
$i++;
}
if ($i == $len) {
if ($lenA == $lenB) {
return 0; // they're the same
} else {
return $lenA < $lenB ? -1 : 1;
}
} else if (ctype_alpha($a[$i])) {
return ctype_alpha($b[$i]) ? strcmp($a[$i], $b[$i]) : -1;
} else {
return ctype_alpha($b[$i]) ? 1 : strcmp($a[$i], $b[$i]);
}
}
Output:
Array
(
[0] => ABC_abc
[1] => ABC_efg
[2] => #$abc
[3] => ##zzAG
)
You write a function sortArray($array, $preset=1) that splits the $array in two arrays.
($preset should be empty by default)
The first array contains all the elements that start with no special sign, the second one contains all elements that start with a special sign. You than sort the firstArray normally (sort()) and print them, and invoke the function on the second array, passing the preset.
(something like
if ($array[i][$preset] != "#") {
array_push ($firstArray ,$array[i]);
} else {
array_push ($secondArray ,$array[i]);
}
sort($firstArray);
print($firstArray);
sortArray($secondArray, $preset++);
)
It's just what came to my mind :)

Categories