Array permutations while maintaining headings - php

I have an array that contains any number of elements, and is allowed to be a multidimensional array, too. My testing example of such array data is:
$arr = array(
array('Material-A', 'Material-B'),
array('Profile-A', 'Profile-B', 'Profile-C'),
array('Thread-A', 'Thread-B'),
// ... any number of elements
);
From this multidimensional array I need to create a single array that is linear in the following format.
$arrFormated = array(
'Material-A',
'Material-A_Profile-A',
'Material-A_Profile-A_Thread-A',
'Material-A_Profile-A_Thread-B',
'Material-A_Profile-A_Thread-C',
'Material-A_Profile-B',
'Material-A_Profile-B_Thread-A',
'Material-A_Profile-B_Thread-B',
'Material-A_Profile-B_Thread-C',
'Material-A_Profile-C',
'Material-A_Profile-C_Thread-A',
'Material-A_Profile-C_Thread-B',
'Material-A_Profile-C_Thread-C',
'Material-B',
'Material-B_Profile-A',
'Material-B_Profile-A_Thread-A'
// Repeat similar pattern found above, etc...
);
For a recursive function, the best that I've been able to come up with thus far is as follows:
private function showAllElements($arr)
{
for($i=0; $i < count($arr); $i++)
{
$element = $arr[$i];
if (gettype($element) == "array") {
$this->showAllElements($element);
} else {
echo $element . "<br />";
}
}
}
However, this code is no where close to producing my desired results. The outcome from the above code is.
Material-A
Material-B
Profile-A
Profile-B
Profile-C
Thread-A
Thread-B
Could somebody please help me with the recursive side of this function so I may get my desired results?

I'd generally recommend thinking about what you want to be recursive. You tried to work with the current element in every recursion step, but your method needs to look at the next array element of the original Array in each recursion step. In this case, it's more useful to pass an index to your recursive function, because the 'current element' (the $arr in showAllElements($arr)) is not helpful.
I think this code should do it:
$exampleArray = array(
array('Material-A', 'Material-B'),
array('Profile-A', 'Profile-B', 'Profile-C'),
array('Thread-A', 'Thread-B','Thread-C'),
// ... any number of elements
);
class StackOverflowQuestion37823464{
public $array;
public function dumpElements($level = 0 /* default parameter: start at first element if no index is given */){
$return=[];
if($level==count($this->array)-1){
$return=$this->array[$level]; /* This is the anchor of the recursion. If the given index is the index of the last array element, no recursion is neccesarry */
}else{
foreach($this->array[$level] as $thislevel) { /* otherwise, every element of the current step will need to be concatenated... */
$return[]=$thislevel;
foreach($this->dumpElements($level+1) as $stringifyIt){ /*...with every string from the next element and following elements*/
$return[]=$thislevel.'_'.$stringifyIt;
}
}
}
return $return;
}
}
$test=new StackOverflowQuestion37823464();
$test->array=$exampleArray;
var_dump($test->dumpElements());

Related

I'm trying to find a element in an array that not repeat

i have to do a function to find a number that not repeat in an array.
It's simple but i have no idea for where begins.
function $returnUnique($arr) {
}
That's quite simple, you need array_filter and array_count_values:
$result = array_filter(array_count_values($array), function ($count)
{
return $count === 1;
});
$result will contain all unique elements from your initial array.
array_search(1, array_count_values($arr))
will find an element (specifically, the first element) that is only found once in the array.

create indexed array inside preg_replace_callback function

I have simple code to replace links in text with numbers 1 to whatever the number of links in text is.
echo preg_replace_callback('/regex/',
function ($links) {
$reg = "/regex/i";
preg_match($reg, $links[0], $url);
static $count = 1;
return '['. $count++ .']';
}, $html);
This is working ok. Now I want to add same number if same links are used in text more times. What I came up with is to create indexed array and inside the function compare current link to existing links in array. If same is found then already indexed link is used along with index number(which will be the link number in text) .
Problem: when I create and add urls to index inside function like this:
$arr=array();
$array[] = $url[0];
var_dump($arr) shows all links with same index number 0. How can I solve this? Thank you.
You are probably getting this if you declare your array inside the callback as this function is called once for each item and so doesn't remember previous values.
One simple way is to define the array outside and use() the value in your callback, which allows the function to access the variable outside it's scope...
$arr=array();
echo preg_replace_callback('/regex/',
function ($links) use (&$arr) {
$reg = "/regex/i";
preg_match($reg, $links[0], $url);
if ( isset($arr[$url[0]]) ) {
$count = ++$arr[$url[0]];
}
else {
$count = 0;
$arr[$url[0]] = $count;
}
return '['. $count++ .']';
}, $html);
Mandatory Note: (for me anyway) processing HTML/XML is usually better done using something like DOMDocument as it can understand both the structure and semantics of the document.

Remove first element from simple array in loop

This question has been asked a thousand times, but each question I find talks about associative arrays where one can delete (unset) an item by using they key as an identifier. But how do you do this if you have a simple array, and no key-value pairs?
Input code
$bananas = array('big_banana', 'small_banana', 'ripe_banana', 'yellow_banana', 'green_banana', 'brown_banana', 'peeled_banana');
foreach ($bananas as $banana) {
// do stuff
// remove current item
}
In Perl I would work with for and indices instead, but I am not sure that's the (safest?) way to go - even though from what I hear PHP is less strict in these things.
Note that after foreach has run, I expected var_dump($bananas) to return an empty array (or null, but preferably an empty array).
1st method (delete by value comparison):
$bananas = array('big_banana', 'small_banana', 'ripe_banana', 'yellow_banana', 'green_banana', 'brown_banana', 'peeled_banana');
foreach ($bananas as $key=>$banana) {
if($banana=='big_banana')
unset($bananas[$key]);
}
2nd method (delete by key):
$bananas = array('big_banana', 'small_banana', 'ripe_banana', 'yellow_banana', 'green_banana', 'brown_banana', 'peeled_banana');
unset($bananas[0]); //removes the first value
unset($bananas[count($bananas)-1]); //removes the last value
//unset($bananas[n-1]); removes the nth value
Finally if you want to reset the keys after deletion process:
$bananas = array_map('array_values', $bananas);
If you want to empty the array completely:
unset($bananas);
$bananas= array();
it still has the indexes
foreach ($bananas as $key => $banana) {
// do stuff
unset($bananas[$key]);
}
for($i=0; $i<count($bananas); $i++)
{
//doStuff
unset($bananas[$i]);
}
This will delete every element after its use so you will eventually end up with an empty array.
If for some reason you need to reindex after deleting you can use array_values
How about a while loop with array_shift?
while (($item = array_shift($bananas)) !== null)
{
//
}
Your Note: Note that after foreach has run, I expected var_dump($bananas) to return an empty array (or null, but preferably
an empty array).
Simply use unset.
foreach ($bananas as $banana) {
// do stuff
// remove current item
unset($bananas[$key]);
}
print_r($bananas);
Result
Array
(
)
This question is old but I will post my idea using array_slice for new visitors.
while(!empty($bananas)) {
// ... do something with $bananas[0] like
echo $bananas[0].'<br>';
$bananas = array_slice($bananas, 1);
}

php get array element by position instead of numeric key

I have a script that sorts input taking into account parent-child relations and the given display-order of each. A simplified array could look like this (the actual array has sub-arrays for children as well)
$output = Array
(
[7] => first array
[3] => second array
[1] => last array
)
In which the keys are the correspondings id's of the input. Now I wish to pass through this array from top to bottom in a while loop. I am not using foreach because if it has children multiple elements should be processed together, and not come again in the next 'loop'.
function recursive_func($array){
while ($i<=count($array)){
if (isset($array[$i]['children'])){
?><div><?php
recursive_function($array[$i]['children']);
$i++;
recursive_function($array[$i]['children']);
$i++;
?></div><?php
}
else{
?><div>Something</div><?php
$i++;
}
}
}
Clearly $array[$i]['children'] aren't the children of the i'th element (by position), but of the key with value i.
How can I pass through this array in the order as in $output?
You can use array_keys to get the keys in sorted order, and iterate through those.
Or can also use array_values, then you can index sequentially. Just do it right at the start.
function recursivefunction( $array ) {
$array = array_values($array);
....
}
I'm not sure why one entry having children means the next does as well, but I'll assume foreach is problematic.
Since the $output keys are not in order, one way is to do the following:
First get all the array keys:
$keys=array_keys($output);
Next, you may call the recursive_func($keys,$output):
function recursive_func($keys,$output){
$size=count($keys);
$i=0;
while ($i<=$size){
if (isset($output[$i]['children'])){
?><div><?php
$a=$output[$i]['children'];
recursive_function(array_keys($a),$a);
$i++;
$a=$output[$i]['children'];
recursive_function(array_keys($a),$a);
$i++;
?></div><?php
}
else{
?><div>Something</div><?php
$i++;
}
}
}
Please note that it is better that you set the $size of the array outside of the loop for better performance
As Garr Godfrey suggested, you can solve this with array_keys() like so
function recursive_func($array){
$keys = array_keys($array);
for ($i=0; $i<count($keys); $i++) {
if (isset($array[ $keys[$i] ]['children'])) {
recursive_func($array[ $keys[$i] ]['children']);
$i++;
recursive_func($array[ $keys[$i] ]['children']);
} else {
//sth, no $i++ here!
}
}
}
Because I am using a for loop here, the $i++ inside the loop will make it possible for you to skip one element

Checking the first element of array, regardless of array indexes

I have a need to check if the elements in an array are objects or something else. So far I did it like this:
if((is_object($myArray[0]))) { ... }
However, on occasion situations dictate that the input array does not have indexes that start with zero (or aren't even numeric), therefore asking for $myArray[0] will generate a Notice, but will also return the wrong result in my condition if the first array element actually is an object (but under another index).
The only way I can think of doing here is a foreach loop where I would break out of it right on the first go.
foreach($myArray as $element) {
$areObjects = (is_object($element));
break;
}
if(($areObjects)) { ... }
But I am wondering if there is a faster code than this, because a foreach loop seems unnecessary here.
you can use reset() function to get first index data from array
if(is_object(reset($myArray))){
//do here
}
You could get an array of keys and get the first one:
$keys = array_keys($myArray);
if((is_object($myArray[$keys[0]]))) { ... }
try this
reset($myArray);
$firstElement = current($myArray);
current gets the element in the current index, therefore you should reset the pointer of the array to the first element using reset
http://php.net/manual/en/function.current.php
http://php.net/manual/en/function.reset.php

Categories