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;
?>
Related
I have tried for a long time but couldn't find a way to merge an array in to a new one.
Mostly I get lost in looping and matching.;(
I would like to recieve a php 5 method that can do the following:
Example 1
Lets say there is an array with url's like:
Array(
'a',
'a/b/c',
'a/b/c/d/e',
'a/y',
'b/z',
'b/z/q/',
)
Every last folder of the url's is the folder where a user has the right to view.
I would like to send the array to a method that returns a new array like:
Array[](
'a/c/e'
'a/y'
'z/q'
)
The method has combined some elements of the origninal array into one element.
This because there is a match in allowed ending folders.
Example 2
Array(
'projects/projectA/books'
'projects/projectA/books/cooking/book1'
'projects/projectA/walls/wall'
'projects/projectX/walls/wall'
'projects/projectZ/'
'projects/projectZ/Wood/Cheese/Bacon'
)
I would like to get a an array like:
Array[](
'books/book1'
'wall'
'wall'
'projectZ/Bacon'
)
Then it would be great (specialy in case of the 'wall' values) to have some references to the full path's of the original array.
Do it like below:-
<?php
$array = Array(
'projects/projectA/books',
'projects/projectA/books/cooking/book1',
'projects/projectA/walls/wall',
'projects/projectX/walls/wall',
'projects/projectZ/',
'projects/projectZ/Wood/Cheese/Bacon'
);// original array
$final_array =array(); // new array variable
foreach($array as $key=>$arr){ // iterate over original array
$exploded_string = end(array_filter(explode('/',$arr))); // get last-value from the url string
foreach($array as $ar){ // iterate again the original array to compare this string withh each array element
$new_exploded_string = end(array_filter(explode('/',$ar))); // get the new-last-values from url string again
if($arr !== $ar && strpos($ar,$exploded_string) !==false){ // if both old and new url strings are not equal and old-last-value find into url string
if($exploded_string == $new_exploded_string ){ // if both new-last-value and old-last-value are equal
$final_array[] = $exploded_string;
}else{
$final_array[] = $exploded_string.'/'.$new_exploded_string ;
}
}
}
}
print_r($final_array);
Output:-https://eval.in/846738
Well, there isn't a single built-in function for this ;)
$items = array(
'projects/projectA/books',
'projects/projectA/books/cooking/book1',
'projects/projectA/walls/wall',
'projects/projectX/walls/wall',
'projects/projectZ/',
'projects/projectZ/Wood/Cheese/Bacon',
'hold/mold/gold/sold/fold',
'hold/mold/gold',
'raja/maza/saza',
'raja/maza',
'mohit/yenky/client/project',
);
echo '$items = ' . nl2br(htmlspecialchars(print_r($items, true))); //Debug
// Sort, so the shorter basePath comes before the longer subPath
usort($items, function($a, $b) {
if (strlen($a) == strlen($b)) {
return 0;
} else {
return strlen($a) > strlen($b) ? 1 : -1;
}
});
$result = array();
while($basePath = array_shift($items)) { // As long as there is a next item
$basePath = rtrim($basePath, '/'); // Right trim extra /
foreach($items as $idx => $subPath) {
if (strpos($subPath, $basePath . '/') === 0) {
// $subPath begins with $basePath
$result[] = preg_replace('#.*/#', '', $basePath) . '/' . preg_replace('#.*/#', '', rtrim($subPath, '/'));
unset($items[$idx]); // Remove item from array, so it won't be matched again
continue 2; // Continue with next while($basePath = array_shift($items))
}
}
// No subPath found, otherwise continue would have called (skipping below code)
$result[] = preg_replace('#.*/#', '', $basePath);
}
echo '$result = ' . nl2br(htmlspecialchars(print_r($result, true))); //Debug
PHPFiddle: http://phpfiddle.org/main/code/ugq9-hy0i
You can avoid using nested loops (and, actually, you should avoid):
sort($array);
$carry = array_shift($array);
$result = [];
$i = 0;
$lastItem = array_reduce($array, function ($carry, $item) use (&$result, &$i) {
$result[$i] = isset($result[$i])
? array_merge($result[$i], [basename($carry)])
: [basename($carry)];
if (strpos($item, $carry) !== 0) {
$i += 1;
}
return $item;
}, $carry);
if (!empty($lastItem)) {
$result[$i] = isset($result[$i])
? array_merge($result[$i], [basename($lastItem)])
: [basename($lastItem)];
}
$result = array_map(function ($item) {
return implode('/', $item);
}, $result);
Here is working demo.
We use array_reduce here to get access to the previously processed item. Also, PHP has function basename, that retrieves the basename. So you can use it and do not reinvent the wheel.
How can I check if a string contains a member of an array, and return the index (integer) of the relevant member?
Let's say my string is this :
$string1 = "stackoverflow.com";
$string2 = "superuser.com";
$r = array("queue" , "stack" , "heap");
get_index($string1 , $r); // returns 1
get_index($string2 , $r); // returns -1 since string2 does not contain any element of array
How can I write this function in an elegant (short) and efficient way ?
I found a function (expression ? ) that checks if the string contains a member of an array :
(0 < count(array_intersect(array_map('strtolower', explode(' ', $string)), $array)))
but this is a boolean. does the count() function return what I want in this statement ?
Thanks for any help !
function get_index($str, $arr){
foreach($arr as $key => $val){
if(strpos($str, $val) !== false)
return $key;
}
return -1;
}
Demo: https://eval.in/95398
This will find the number of matching elements in your array, if you want all matching keys, use the commented lines instead:
function findMatchingItems($needle, $haystack){
$foundItems = 0; // start counter
// $foundItems = array(); // start array to save ALL keys
foreach($haystack as $key=>$value){ // start to loop through all items
if( strpos($value, $needle)!==false){
++$foundItems; // if found, increase counter
// $foundItems[] = $key; // Add the key to the array
}
}
return $foundItems; // return found items
}
findMatchingItems($string1 , $r);
findMatchingItems($string2 , $r);
If you want to return all matching keys, just change $foundItems to an array and add the keys in the if-statement (switch to the commented lines).
If you only want to know if something matches or not
function findMatchingItems($needle, $haystack){
if( strpos($value, $needle)!==false){
return true;
break; // <- This is important. This stops the loop, saving time ;)
}
return false;// failsave, if no true is returned, this will return
}
I would do a function like this:
function getIndex($string, $array) {
$index = -1;
$i = 0;
foreach($array as $array_elem) {
if(str_pos($array_elem, $string) !== false) {
$index = $i;
}
$i++;
}
return $index;
}
I have this code:
$getClass = $params->get('pageclass_sfx');
var_dump($getClass); die();
The code above returns this:
string(24) "sl-articulo sl-categoria"
How can I retrieve the specific word I want without mattering its position?
Ive seen people use arrays for this but that would depend on the position (I think) that you enter these strings and these positions may vary.
For example:
$myvalue = $params->get('pageclass_sfx');
$arr = explode(' ',trim($myvalue));
echo $arr[0];
$arr[0] would return: sl-articulo
$arr[1] would return: sl-categoria
Thanks.
You can use substr for that in combination with strpos:
http://nl1.php.net/substr
http://nl1.php.net/strpos
$word = 'sl-categoria';
$page_class_sfx = $params->get('page_class_sfx');
if (false !== ($pos = strpos($page_class_sfx, $word))) {
// stupid because you already have the word... But this is what you request if I understand correctly
echo 'found: ' . substr($page_class_sfx, $pos, strlen($word));
}
Not sure if you want to get a word from the string if you already know the word... You want to know if it's there? false !== strpos($page_class_sfx, $word) would be enough.
If you know exactly what strings you're looking for, then stripos() should be sufficient (or strpos() if you need case-sensitivity). For example:
$myvalue = $params->get('pageclass_sfx');
$pos = stripos($myvalue, "sl-articulo");
if ($pos === FALSE) {
// string "sl-articulo" was not found
} else {
// string "sl-articulo" was found at character position $pos
}
If you need to check if some word are in string you may use preg_match function.
if (preg_match('/some-word/', 'many some-words')) {
echo 'some-word';
}
But this solution can be used for a small list of needed words.
For other cases i suggest you to use some of this.
$myvalue = $params->get('pageclass_sfx');
$arr = explode(' ',trim($myvalue));
$result = array();
foreach($arr as $key=> $value) {
// This will calculates all data in string.
if (!isset($result[$value])) {
$result[$value] = array(); // or 0 if you don`t need to use positions
}
$result[$value][] = $key; // For all positions
// $result[$value] ++; // For count of this word in string
}
// You can just test some words like follow:
if (isset($result['sl-categoria'])) {
var_dump($result['sl-categoria']);
}
I need to make app with will fill array with some random values, but if in array are duplicates my app not working correctly. So I need to write script code which will find duplicates and replace them with some other values.
Okay so for example i have an array:
<?PHP
$charset=array(123,78111,0000,123,900,134,00000,900);
function arrayDupFindAndReplace($array){
// if in array are duplicated values then -> Replace duplicates with some other numbers which ones I'm able to specify.
return $ArrayWithReplacedValues;
}
?>
So result shall be the same array with replaced duplicated values.
You can just keep track of the words that you've seen so far and replace as you go.
// words we've seen so far
$words_so_far = array();
// for each word, check if we've encountered it so far
// - if not, add it to our list
// - if yes, replace it
foreach($charset as $k => $word){
if(in_array($word, $words_so_far)){
$charset[$k] = $your_replacement_here;
}
else {
$words_so_far[] = $word;
}
}
For a somewhat-optimized solution (for cases where there are not that many duplicates), use array_count_values() (reference here) to count the number of times it shows up.
// counts the number of words
$word_count = array_count_values($charset);
// words we've seen so far
$words_so_far = array();
// for each word, check if we've encountered it so far
// - if not, add it to our list
// - if yes, replace it
foreach($charset as $k => $word){
if($word_count[$word] > 1 && in_array($word, $words_so_far)){
$charset[$k] = $your_replacement_here;
}
elseif($word_count[$word] > 1){
$words_so_far[] = $word;
}
}
Here the example how to generate unique values and replace recurring values in array
function get_unique_val($val, $arr) {
if ( in_array($val, $arr) ) {
$d = 2; // initial prefix
preg_match("~_([\d])$~", $val, $matches); // check if value has prefix
$d = $matches ? (int)$matches[1]+1 : $d; // increment prefix if exists
preg_match("~(.*)_[\d]$~", $val, $matches);
$newval = (in_array($val, $arr)) ? get_unique_val($matches ? $matches[1].'_'.$d : $val.'_'.$d, $arr) : $val;
return $newval;
} else {
return $val;
}
}
function unique_arr($arr) {
$_arr = array();
foreach ( $arr as $k => $v ) {
$arr[$k] = get_unique_val($v, $_arr);
$_arr[$k] = $arr[$k];
}
unset($_arr);
return $arr;
}
$ini_arr = array('dd', 'ss', 'ff', 'nn', 'dd', 'ff', 'vv', 'dd');
$res_arr = unique_arr($ini_arr); //array('dd', 'ss', 'ff', 'nn', 'dd_2', 'ff_2', 'vv', 'dd_3');
Full example you can see here webbystep.ru
Use the function
array_unique()
See more info at http://php.net/manual/en/function.array-unique.php
$uniques = array();
foreach ($charset as $value)
$uniques[$value] = true;
$charset = array_flip($uniques);
I have two arrays that I'm comparing and I'd like to know if there is a more efficient way to do it.
The first array is user submitted values, the second array is allowed values some of which may contain a wildcard in the place of numbers e.g.
// user submitted values
$values = array('fruit' => array(
'apple8756apple333',
'banana234banana',
'apple4apple333',
'kiwi435kiwi'
));
//allowed values
$match = array('allowed' => array(
'apple*apple333',
'banana234banana',
'kiwi*kiwi'
));
I need to know whether or not all of the values in the first array, match a value in the second array.
This is what I'm using:
// the number of values to validate
$valueCount = count($values['fruit']);
// the number of allowed to compare against
$matchCount = count($match['allowed']);
// the number of values passed validation
$passed = 0;
// update allowed wildcards to regular expression for preg_match
foreach($match['allowed'] as &$allowed)
{
$allowed = str_replace(array('*'), array('([0-9]+)'), $allowed);
}
// for each value match against allowed values
foreach($values['fruit'] as $fruit)
{
$i = 0;
$status = false;
while($i < $matchCount && $status == false)
{
$result = preg_match('/' . $match['allowed'][$i] . '/', $fruit);
if ($result)
{
$status = true;
$passed++;
}
$i++;
}
}
// check all passed validation
if($passed === $valueCount)
{
echo 'hurray!';
}
else
{
echo 'fail';
}
I feel like I might be missing out on a PHP function that would do a better job than a while loop within a foreach loop. Or am I wrong?
Update: Sorry I forgot to mention, numbers may occur more than 1 place within the values, but there will only ever be 1 wildcard. I've updated the arrays to represent this.
If you don't want to have a loop inside another, it would be better if you grouped your $match regex.
You could get the whole functionality with a lot less code, which might arguably be more efficient than your current solution:
// user submitted values
$values = array(
'fruit' => array(
'apple8756apple',
'banana234banana',
'apple4apple',
'kiwi51kiwi'
)
);
$match = array(
'allowed' => array(
'apple*apple',
'banana234banana',
'kiwi*kiwi'
)
);
$allowed = '('.implode(')|(',$match['allowed']).')';
$allowed = str_replace(array('*'), array('[0-9]+'), $allowed);
foreach($values['fruit'] as $fruit){
if(preg_match('#'.$allowed.'#',$fruit))
$matched[] = $fruit;
}
print_r($matched);
See here: http://codepad.viper-7.com/8fpThQ
Try replacing /\d+/ in the first array with '*', then do array_diff() between the 2 arrays
Edit: after clarification, here's a more refined approach:
<?php
$allowed = str_replace("*", "\d+", $match['allowed']);
$passed = 0;
foreach ($values['fruit'] as $fruit) {
$count = 0;
preg_replace($allowed, "", $fruit, -1, $count); //preg_replace accepts an array as 1st argument and stores the replaces done on $count;
if ($count) $passed++;
}
if ($passed == sizeof($values['fruit']) {
echo 'hurray!';
} else {
echo 'fail';
}
?>
The solution above does not remove the need for a nested loop, but it merely lets PHP do the inner loop, which may be faster (you should actually benchmark it)