I have array like this
array (size=6)
0 => string '2 16 10 4 0 0 0 0 0'
1 => string '0 0 0 4'
2 => string '2 15 8 6 0 0 0 0 0'
3 => string '0 0 0 3'
4 => string '3 18 12 5 0 0 0 0 0'
5 => string '0 0 0 2'
I want to divide the array and create a new array like
array1 (size = 1)
0 => '2 16 10 4 0 0 0 0 0 0 0 0 0 4'
array2 (size = 1)
0 => '2 15 8 6 0 0 0 0 0 0 0 0 3'
array3 (size = 2)
0 => '3 18 12 5 0 0 0 0 0 0 0 0 2'
array_chunk() works fine. But it not supported my array
use array_chunk($array_name, 2)
the above will return a multi dimension array.
You can do it through array_chunk() and foreach()
$new_array = array_chunk($original_array,2);
$final_array = [];
foreach($new_array as $arr){
$final_array[] = $arr[0].' '.$arr[1];
}
print_r($final_array);
Output:- https://eval.in/928261
Note:- If you want to remove extra white-spaces in-between the strings, then use preg_replace()
$new_array = array_chunk($original_array,2);
$final_array = [];
foreach($new_array as $arr){
$final_array[] = preg_replace('/\s+/', ' ', $arr[0]).' '.preg_replace('/\s+/', ' ', $arr[1]);
}
print_r($final_array);
Output:-https://eval.in/928265
Method #1: (Demo)
$prepped_copy=preg_replace('/\s+/',' ',$array); // reduce spacing throughout entire array
while($prepped_copy){ // iterate while there are any elements in the array
$result[]=implode(' ',array_splice($prepped_copy,0,2)); // concat 2 elements at a time
}
var_export($result);
Method #2 (Demo)
$pairs=array_chunk(preg_replace('/\s+/',' ',$array),2); // reduce spacing and pair elements
foreach($pairs as $pair){
$result[]="{$pair[0]} {$pair[1]}"; // concat 2 elements at a time
}
var_export($result);
Both Output:
array (
0 => '2 16 10 4 0 0 0 0 0 0 0 0 4',
1 => '2 15 8 6 0 0 0 0 0 0 0 0 3',
2 => '3 18 12 5 0 0 0 0 0 0 0 0 2',
)
To my surprise, Method #1 was actually slightly faster using the small sample dataset (but not noticeably so).
Related
I've array MxN of zeros (0). I need to fill it with 20 truths (1) by random postions.
An example
1 1 1 0 1 0 1
0 0 0 0 0 0 0
0 1 0 1 0 1 1
0 0 0 0 1 1 1
0 0 1 0 0 0 0
0 0 1 0 1 1 0
1 1 0 1 1 0 0
I fill it by non-determine algorithm:
$amountUnits = 20;
while($amountUnits > 0) {
$i = rand(0, $M-1);
$j = rand(0, $N-1);
if(!$grid[$i][$j]) {
$grid[$i][$j] = 1;
$amountUnits--;
}
}
But it's solved in random time. How can I fill it throught seed or something else? And where I can read about this problem?
Please excuse my bad English.
Thank you!
Fill a 1-dimensional array x times with 1 and the rest with 0. shuffle () shuffles the array.
array_chunk divides the array so that a matrix (a 2-dimensional array) is created.
$rows = 7;
$cols = 7;
$fillTrue = 20;
$arr = array_fill(0,$fillTrue,1)+array_fill($fillTrue, $rows*$cols-$fillTrue,0);
shuffle($arr);
$arr = array_chunk($arr,$cols);
Updated
So it turns out that PHP has a shuffle function, and #jspit's answer shows you how to use it. His answer is the php way to implement my answer.
Original Answer
Fill the array with 0's, and then add all of the 1's in the first rows and columns. So if you have an array that's 4 rows and 5 columns, and you want 7 1's, it would look like this:
1 1 1 1 1
1 1 0 0 0
0 0 0 0 0
0 0 0 0 0
Now, do a Fischer-Yates shuffle to distribute the 1's around randomly.
Normally, you do that shuffle on a 1-dimensional array. But you can map a 1-dimensional array index to two dimensions with some simple arithmetic, as shown below in pseudo-code. (Sorry, but I'm not really fluent in php.)
// shuffle a 2-dimensional array
for (i = numRows * numCols; i > 1; --i)
j = random(0, i) // picks a number from 0 to i-1
// get row and column for i
irow = (i-1) / numCols
icol = (i-1) % numCols
// get row and column for j
jrow = j / numCols
jcol = j % numCols
// and swap the items
temp = array[irow, icol]
array[irow, icol] = array[jrow, jcol]
array[jrow, jcol] = temp
It seems like you could do this (since it's really just a chopped up string of random digits?):
function truths(int $truths, int $many): array {
$facts = array_fill(0, $truths, true);
$statements = array_fill(0, $many, false);
foreach ($statements as $assertion => $statement) {
$statements[$assertion] = $facts[$assertion] ?? false;
}
shuffle($statements);
return $statements;
}
Then you give a function the number of truths and grid dimensions, and it will generate the output:
function truth_grid(int $truths, int $rows, int $columns) {
return chunk_split(implode(' ', array_map('intval',
truths($truths, $rows * $columns)
)), $columns * 2);
}
Given:
$set = [[4, 3, 3], [10, 4, 5], [12, 3, 9], [5, 2, 10],];
foreach($set as [$truths, $rows, $columns]) {
print_r(
sprintf('%d of %d x %d', $truths, $rows, $columns).PHP_EOL.PHP_EOL.
truth_grid($truths, $rows, $columns).PHP_EOL
);
}
The readout of which is:
4 of 3 x 3
1 0 0
1 0 1
1 0 0
10 of 4 x 5
1 0 0 0 1
0 1 0 0 1
1 1 0 0 0
1 1 1 0 1
12 of 3 x 9
0 0 0 0 1 1 0 0 0
0 0 0 1 1 1 1 0 1
1 1 1 0 0 1 0 0 1
5 of 2 x 10
0 0 0 0 0 0 0 0 1 1
0 0 1 0 0 0 1 0 0 1
And if you're looking for chunked arrays of the same shape:
function truth_chunks(int $truths, int $rows, int $columns) {
return array_chunk(truths($truths, $rows * $columns), $columns);
}
I have an array $d_visitors = array_count_values($d_visitors);
array:7 [▼
2 => 4
5 => 1
8 => 2
3 => 1
1 => 2
9 => 3
0 => 2
]
I'm trying to loop through that array 24 times, and check if the key matches, and store its value.
$dv = [];
for ($i = 0; $i < 24; $i++){
foreach ($d_visitors as $k =>$v) {
if($i == $k ){
$dv[$i] = $v;
}else{
$dv[$i] = 0;
}
}
}
I'm trying to print out something like this:
array:24 [▼
0 => 2
1 => 2
2 => 4
3 => 1
4 => 0
5 => 1
6 => 0
7 => 0
8 => 2
9 => 3
10 => 0
11 => 0
12 => 0
13 => 0
14 => 0
15 => 0
16 => 0
17 => 0
18 => 0
19 => 0
20 => 0
21 => 0
22 => 0
23 => 0
]
But I kept getting this:
array:24 [▼
0 => 2
1 => 0
2 => 0
3 => 0
4 => 0
5 => 0
6 => 0
7 => 0
8 => 0
9 => 0
10 => 0
11 => 0
12 => 0
13 => 0
14 => 0
15 => 0
16 => 0
17 => 0
18 => 0
19 => 0
20 => 0
21 => 0
22 => 0
23 => 0
]
Try this way:
$dv = [];
for ($i = 0; $i < 24; $i++){
$dv[$i] = 0;
if (isset($d_visitors[$i])) {
$dv[$i] = $d_visitors[$i];
}
}
More simplified is:
$dv = [];
for ($i = 0; $i < 24; $i++){
$dv[$i] = isset($d_visitors[$i])? $d_visitors[$i] : 0;
}
The problem in your code is in line $dv[$i] = 0; as it sets to zero $dv[$i] which earlier has been set.
You need to use one flag variable. Your code is also correct.
Try like this:
$dv = [];
$flag = 0;
for ($i = 0; $i < 24; $i++){
$flag = 0;
foreach ($d_visitors as $k =>$v) {
if($i == $k ){
$dv[$i] = $v;
$flag = 1;
}
}
if($flag == 0){
$dv[$i] = 0;
}
}
Another way of asking your process is:
How can I:
merge a default array with another array based on keys
and ksort() the result array?
While you can achieve your desired result using a foreach() loop and a condition statement on each iteration, I can show you a more concise, simple approach:
This is your new array of data: $array=[2=>4,5=>1,8=>2,3=>1,1=>2,9=>3,0=>2];
There are two ways to set up your default data array:
$defaults=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; // 24 elements with 0 value
or more elegantly:
$defaults=array_fill(0,24,0);
Then you only need to call array_replace() to overwrite the default values with the new values. This will keep the keys in ASC order.
var_export(array_replace($defaults,$array));
You can even nest the function calls and avoid adding variable names to the global scope like this:
$d_visitors=array_replace(array_fill(0,24,0),array_count_values($d_visitors)));
Done -- merged and ksorted.
To show some other ways that programmers might try to combine the two arrays (fruitlessly or illogically), here is a demonstration.
I am building a word unscrambler (php/mysql) that takes user input of between 2 and 8 letters and returns words of between 2 and 8 letters that can be made from those letters, not necessarily using all of the letters, but definitely not including more letters than supplied.
The user will enter something like MSIKE or MSIKEI (two i's), or any combination of letters or multiple occurrences of a letter.
The query below will find all occurrences of words that contain M, S, I, K, or E.
However, the query below also returns words that have multiple occurrences of letters not requested. For example, the word meek would be returned, even though it has two e's and the user didn't enter two e's, or the word kiss, even though the user didn't enter s twice.
SELECT word
FROM words
WHERE word REGEXP '[msike]'
AND has_a=0
AND has_b=0
AND has_c=0
AND has_d=0
(we skip e) or we could add has_e=1
AND has_f=0
...and so on...skipping letters m, s, i, k, and e
AND has_w=0
AND has_x=0
AND has_y=0
AND has_z=0
Note the columns has_a, has_b, etc are either 1 if the letter occurs in the word or 0 if not.
I am open to any changes to the table schema.
This site: http://grecni.com/texttwist.php is a good example of what I am trying to emulate.
Question is how to modify the query to not return words with multiple occurrences of a letter, unless the user specifically entered a letter multiple times. Grouping by word length would be an added bonus.
Thanks so much.
EDIT: I altered the db per the suggestion of #awei, The has_{letter} is now count_{letter} and stores the total number of occurrences of the respective letter in the respective word. This could be useful when a user enters a letter multiple times. example: user enters MSIKES (two s).
Additionally, I have abandoned the REGEXP approach as shown in the original SQL statement. Working on doing most of the work on the PHP side, but many hurdles still in the way.
EDIT: Included first 10 rows from table
id word alpha otcwl ospd csw sowpods dictionary enable vowels consonants start_with end_with end_with_ing end_with_ly end_with_xy count_a count_b count_c count_d count_e count_f count_g count_h count_i count_j count_k count_l count_m count_n count_o count_p count_q count_r count_s count_t count_u count_v count_w count_x count_y count_z q_no_u letter_count scrabble_points wwf_points status date_added
1 aa aa 1 0 0 1 1 1 aa a a 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 1 2015-11-12 05:39:45
2 aah aah 1 0 0 1 0 1 aa h a h 0 0 0 2 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 6 5 1 2015-11-12 05:39:45
3 aahed aadeh 1 0 0 1 0 1 aae hd a d 0 0 0 2 0 0 1 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 9 8 1 2015-11-12 05:39:45
4 aahing aaghin 1 0 0 1 0 1 aai hng a g 1 0 0 2 0 0 0 0 0 1 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 6 10 11 1 2015-11-12 05:39:45
5 aahs aahs 1 0 0 1 0 1 aa hs a s 0 0 0 2 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 4 7 6 1 2015-11-12 05:39:45
6 aal aal 1 0 0 1 0 1 aa l a l 0 0 0 2 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 4 1 2015-11-12 05:39:45
7 aalii aaiil 1 0 0 1 1 1 aaii l a i 0 0 0 2 0 0 0 0 0 0 0 2 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 6 1 2015-11-12 05:39:45
8 aaliis aaiils 1 0 0 1 0 1 aaii ls a s 0 0 0 2 0 0 0 0 0 0 0 2 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 6 6 7 1 2015-11-12 05:39:45
9 aals aals 1 0 0 1 0 1 aa ls a s 0 0 0 2 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 4 4 5 1 2015-11-12 05:39:45
10 aardvark aaadkrrv 1 0 0 1 1 1 aaa rdvrk a k 0 0 0 3 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 2 0 0 0 1 0 0 0 0 0 8 16 17 1 2015-11-12 05:39:45
Think you've already done the hard work with your revised schema. All you need to do now is modify the query to look for <= the number of counts of each letter as specified by the user.
E.g. if the user entered "ALIAS":
SELECT word
FROM words
WHERE count_a <= 2
AND count_b <= 0
AND count_c <= 0
AND count_d <= 0
AND count_e <= 0
AND count_f <= 0
AND count_g <= 0
AND count_h <= 0
AND count_i <= 1
AND count_j <= 0
AND count_k <= 0
AND count_l <= 1
AND count_m <= 0
AND count_n <= 0
AND count_o <= 0
AND count_p <= 0
AND count_q <= 0
AND count_r <= 0
AND count_s <= 1
AND count_t <= 0
AND count_u <= 0
AND count_v <= 0
AND count_w <= 0
AND count_x <= 0
AND count_y <= 0
AND count_z <= 0
ORDER BY CHAR_LENGTH(word), word;
Note: As requested, this is ordering by word length, then alphabetically. Have used <= even for <= 0 just to make it easier to modify by hand for other letters.
This returns "aa", "aal" and "aals" (but not "aalii" or "aaliis" since they both have two "i"s).
See SQL Fiddle Demo.
Since you have two different requirements, I suggest implementing both two different solutions.
Where you don't care about dup letters, build a SET datatype with the 26 letters. Populate the bits according what the word has. This ignores duplicate letters. This also facilitates looking for words with a subset of the letters: (the_set & ~the_letters) = 0.
Where you do care about dups, sort the letters in the word and store that as the key. "msike" becomes "eikms".
Build a table that contains 3 columns:
eikms -- non unique index on this
msike -- the real word - probably good to have this as the PRIMARY KEY
SET('m','s','i',','k','e') -- for the other situation.
msikei and meek would be entered as
eikms
msikei
SET('m','s','i',','k','e') -- (or, if more convenient: SET('m','i','s','i',','k','e')
ekm
meek
SET('e','k','m')
REGEXP is not practical for your task.
Edit 1
I think you also need a column that indicates whether there are any doubled letters in the word. That way, you can distinguish that kiss is allowed for msikes but for for msike.
Edit 2
A SET or an INT UNSIGNED can hold 1 bit for each of the 26 letters -- 0 for not present, 1 for present.
msikes and msike would both go into the set with exactly 5 bits turned on. The value to INSERT would be 'm,s,i,k,e,s' for msikes. Since the rest needs to involve Boolean arithmetic, maybe it would be better to use INT UNSIGNED. So...
a is 1 (1 << 0)
b is 2 (1 << 1)
c is 4 (1 << 2)
d is 8 (1 << 3)
...
z is (1 << 25)
To INSERT you use the | operator. bad becomes
(1 << 1) | (1 << 0) | (1 << 3)
Note how the bits are laid out, with 'a' at the bottom:
SELECT BIN((1 << 1) | (1 << 0) | (1 << 3)); ==> 1011
Similarly 'ad' is 1001. So, does 'ad' match 'bad'? The answer comes from
SELECT b'1001' & ~b'1011' = 0; ==> 1 (meaning 'true')
That means that all the letters in 'ad' (1001) are found in 'bad' (1011). Let's introduce "bed", which is 11010.
SELECT b'11010' & ~b'1011' = 0; ==> FALSE because of 'e' (10000)
But 'dad' (1001) will work fine:
SELECT b'1001' & ~b'1011' = 0; ==> TRUE
So, now comes the "dup" flag. Since 'dad' has dup letters, but 'bad' did not, your rules say that it is not a match. But it took the "dup" to finish the decision.
If you have not had a course in Boolean arithmetic, well, I have just presented the first couple of chapters. If I covered it too fast, find a math book on such and jump in. "It's not rocket science."
So, back to what code is needed to decide whether my_word has a subset of letters and whether it is allowed to have duplicate letters:
SELECT $my_mask & ~tbl.mask = 0, dup FROM tbl;
Then do the suitable AND / OR between to finish the logic.
With the limited Regex support on MySQL, best I can do is a PHP script for generating the query, presuming it only includes English letters. It seems making an expression to exclude invalid words is easier than one that includes them.
<?php
$inputword = str_split('msikes');
$counter = array();
for ($l = 'a'; $l < 'z'; $l++) {
$counter[$l] = 0;
}
foreach ($inputword as $l) {
$counter[$l]++;
}
$nots = '';
foreach ($counter as $l => $c) {
if (!$c) {
$nots .= $l;
unset($counter[$l]);
}
}
$conditions = array();
if(!empty($nots)) {
// exclude words that have letters not given
$conditions[] = "[" . $nots . "]'";
}
foreach ($counter as $l => $c) {
$letters = array();
for ($i = 0; $i <= $c; $i++) {
$letters[] = $l;
}
// exclude words that have the current letter more times than given
$conditions[] = implode('.*', $letters);
}
$sql = "SELECT word FROM words WHERE word NOT RLIKE '" . implode('|', $conditions) . "'";
echo $sql;
Something like this might work for you:
// Input Word
$WORD = strtolower('msikes');
// Alpha Array
$Alpha = range('a', 'z');
// Turn it into letters.
$Splited = str_split($WORD);
$Letters = array();
// Count occurrence of each letter, use letter as key to make it unique
foreach( $Splited as $Letter ) {
$Letters[$Letter] = array_key_exists($Letter, $Letters) ? $Letters[$Letter] + 1 : 1;
}
// Build a list of letters that shouldn't be present in the word
$ShouldNotExists = array_filter($Alpha, function ($Letter) use ($Letters) {
return ! array_key_exists($Letter, $Letters);
});
#### Building SQL Statement
// Letters to skip
$SkipLetters = array();
foreach( $ShouldNotExists as $SkipLetter ) {
$SkipLetters[] = "`has_{$SkipLetter}` = 0";
}
// count condition (for multiple occurrences)
$CountLetters = array();
foreach( $Letters as $K => $V ) {
$CountLetters[] = "`count_{$K}` <= {$V}";
}
$SQL = 'SELECT `word` FROM `words` WHERE '.PHP_EOL;
$SQL .= '('.implode(' AND ', $SkipLetters).')'.PHP_EOL;
$SQL .= ' AND ('.implode(' AND ', $CountLetters).')'.PHP_EOL;
$SQL .= ' ORDER BY LENGTH(`word`), `word`'.PHP_EOL;
echo $SQL;
given following text
bond0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
eth0: 11329920252 12554462 0 0 0 0 0 3561 13072970332 12899522 0 0 0 0 0 0
I need to capture columns values. I thought something about these lines:
Regex: `(\w+):(?:\s+(\d+))+`
Php: `preg_match_all('/(\w+):(?:\s+(\d+))+/sim', $data, $regs)
But unfortunately it captures only first column.
Array
(
[0] => Array
(
[0] => dummy0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
[1] => bond0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
[2] => eth0: 11329920252 12554462 0 0 0 0 0 3561 13072970332 12899522 0 0 0 0 0 0
[3] => ip6tnl0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
[4] => lo: 51675995 100695 0 0 0 0 0 0 51675995 100695 0 0 0 0 0 0
[5] => sit0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
[6] => tunl0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
)
[1] => Array
(
[0] => 0
[1] => 0
[2] => 0
[3] => 0
[4] => 0
[5] => 0
[6] => 0
)
)
Any suggestion? Thanks
`
====EDIT====
Just to be clear: i know that i could preg_match searching for \d+ values or split the whole string in lines and run explode on the each line, but I'm interested in regex solution where I have first column as first member of resulting array(actualy forgot to put capturing braces in the first draft of question), and following columns with data, every line putted in it's dedicated array...
Why use preg_match or preg_match_all at all?
$results = array();
foreach (preg_split("/\r\n|\r|\n/", $data) as $line)
{
list($key, $values) = explode(":", $line);
$results[$key] = preg_split("/\s/", trim($values));
}
This should work as long as there is no more than one : on every line. Seems to me like it's the shortest and fastest way to write this too.
Here you go:
$data = explode("\n", $data);
$out = array();
foreach ($data as $d) {
preg_match_all('/\s(\d+)/', $d, $matches);
Puts $matches[0] equal to an array of matches. You then want to add it to the array of rows:
$out[] = $matches[0];
}
You now have an jagged array of lines and columns. So, to reference line two column four, you can go to $out[1][3].
I know that you are looking for preg_match solution but this is in case you didn't find any usefull answer
<?php
$val = "bond0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
eth0: 11329920252 12554462 0 0 0 0 0 3561 13072970332 12899522 0 0 0 0 0 0";
$arr1 = explode("\n",$val);
foreach ($arr1 as $value) {
$exp = explode(":",$value);
$ex = preg_replace('/\s+/', ' ',trim($exp[1]));
$arr[$exp[0]] = explode(" ",$ex);
}
var_dump($arr);
?>
results:
array (size=2)
'bond0' =>
array (size=17)
0 => string '' (length=0)
1 => string '0' (length=1)
2 => string '0' (length=1)
3 => string '0' (length=1)
4 => string '0' (length=1)
5 => string '0' (length=1)
6 => string '0' (length=1)
7 => string '0' (length=1)
8 => string '0' (length=1)
9 => string '0' (length=1)
10 => string '0' (length=1)
11 => string '0' (length=1)
12 => string '0' (length=1)
13 => string '0' (length=1)
14 => string '0' (length=1)
15 => string '0' (length=1)
16 => string '0' (length=1)
'eth0' =>
array (size=17)
0 => string '' (length=0)
1 => string '11329920252' (length=11)
2 => string '12554462' (length=8)
3 => string '0' (length=1)
4 => string '0' (length=1)
5 => string '0' (length=1)
6 => string '0' (length=1)
7 => string '0' (length=1)
8 => string '3561' (length=4)
9 => string '13072970332' (length=11)
10 => string '12899522' (length=8)
11 => string '0' (length=1)
12 => string '0' (length=1)
13 => string '0' (length=1)
14 => string '0' (length=1)
15 => string '0' (length=1)
16 => string '0' (length=1)
You can do it like this:
$subject = <<<LOD
dummy0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
bond0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
eth0: 11329920252 12554462 0 0 0 0 0 3561 13072970332 12899522 0 0 0 0 0 0
ip6tnl0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
lo: 51675995 100695 0 0 0 0 0 0 51675995 100695 0 0 0 0 0 0
sit0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
tunl0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
LOD;
$pattern = '~^(?<item>\w+):|\G\h+(?<value>\d+)~m';
preg_match_all($pattern, $subject, $matches, PREG_SET_ORDER);
$i=-1;
foreach($matches as $match) {
if (isset($match['value']))
$result[$i]['values'][] = $match['value'];
else {
$i++;
$result[$i]['item'] = $match['item']; }
}
print_r($result);
You will obtain the format you describe in your EDIT.
Pattern details:
~ # pattern delimiter
^ # anchor for the line start (in multiline mode)
(?<item>\w+) # named capture "item"
:
| # OR
\G # force the match to be contigous from precedent
\h+ #
(?<value>\d+) # named capture "value"
~m # pattern delimiter, m modifier for multiline mode
I currently have an anagram solver on my website that works well and quickly.
I use an array structure to hold number values of each letter used in each word. So basically when someone put in the letters "fghdywkjd" My solver will go through each word in its db and match the amout of letters in each word to the values associated with the letter inputted ie. "fghdywkjd"
I build the array like this
$a = array('a' => 1, 'b' => 1, 'c' => 1, 'd' => 1, 'e' => 1, 'f' => 1, 'g' => 1, 'h' => 1, 'i' => 1, 'j' => 1, 'k' => 1, 'l' => 1, 'm' => 1, 'n' => 1, 'o' => 1, 'p' => 1, 'q' => 1, 'r' => 1, 's' => 1, 't' => 1, 'u' => 1, 'v' => 1, 'w' => 1, 'x' => 1, 'y' => 1, 'z' => 1);
It counts the values as it goes through each word.
I am trying to think of the best way to add a blank tile feature to it that is not going to slow it down.
The only way I can figure out how to add this feature is to wait till I have all my results then take each word found and add the letter "a" and find possibilities, then add the latter "b" and so on. For each word that would be enormous.
Anyways some ideas?
Here's probably how I would do it. I would set up the word database table structure like this: (The main reason for this is speed. We could split the names by letter each query but I think this way is faster though I haven't benchmarked).
name a b c d e f g h i j k l m n o p q r s t u v w x y z
---- - - - - - - - - - - - - - - - - - - - - - - - - - -
test 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 0 0 0 0 0 0
tests 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 0 0 0 0 0 0
foo 0 0 0 0 0 1 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0
and then in the PHP I'd do this: This assumes that the number of letters in the word has to match the anagram exactly (no extra letters).
<?php
$letters = array_fill_keys (range('a', 'z'), 0);
$word = 'set'; // start with the word 'set'
$wordLetters = str_split(preg_replace("/[^a-z]/", '', strtolower($word))); // remove invalid letters, lowercase, and convert to array
$numberOfWildcards = 1; // Change this to the number of wildcards you want
foreach ($wordLetters as $letter) {
$letters[$letter]++;
}
$query = 'SELECT `name`, 0';
foreach ($letters as $letter => $num) {
// $query .= "+ABS(`$letter`-$num)";
$query .= "+IF(`$letter` > $num, `$letter` - $num, 0)";
}
$query = ' AS difference
FROM `word_table`
WHERE
LENGTH(`name`) = ' . (strlen($word) + $numberOfWildcards) . '
HAVING
difference = ' . $numberOfWildcards;
If you want to see the difference between the word you are checking and all the words in the database get rid of the where and having clauses.
Let me know how this works out for you.