I want to get all permutations from elements of array. Source array is very simple:
$arr = [ 1,2,3,4 ];
I wrote the code for implement Heap's algorithm,
private function mixture( $size, array $collection ) {
$permutations = [];
$offset = $size - 1;
if ( 1 === $size ) {
$permutations[] = implode( '-', $collection );
return $permutations;
}
for ( $i = 0; $i < $offset; $i++ ) {
$permutations = array_merge( $permutations, $this->mixture( $offset, $collection ) );
$j = ( 0 == $size % 2 ) ? $i : 0;
$tmp_el = $collection[ $offset ];
$collection[ $offset ] = $collection[ $j ];
$collection[ $j ] = $tmp_el;
}
$permutations = array_merge( $permutations, $this->mixture( $offset, $collection ) );
return $permutations;
}
The result of works has a many of duplications
array (size=24)
0 => '1-2-3-4' << same 4
1 => '2-1-3-4' << same 5
2 => '3-2-1-4'
3 => '2-3-1-4'
4 => '1-2-3-4' << same 0
5 => '2-1-3-4' < same 1
6 => '4-2-3-1'
7 => '2-4-3-1'
8 => '3-2-4-1'
9 => '2-3-4-1'
10 => '4-2-3-1'
11 => '2-4-3-1'
12 => '4-1-3-2'
13 => '1-4-3-2'
14 => '3-1-4-2'
15 => '1-3-4-2'
16 => '4-1-3-2'
17 => '1-4-3-2'
18 => '4-1-2-3'
19 => '1-4-2-3'
20 => '2-1-4-3'
21 => '1-2-4-3'
22 => '4-1-2-3'
23 => '1-4-2-3'
Please, help me to understand a reason for this and fix the code. I want to remove any duplication from the result.
Thanks
Your only problem is that you need to pass the $collection by reference because PHP creates an array copy by default:
mixture( $size, array &$collection )
https://3v4l.org/7Vn2p
<?php
$arr = [ 1,2,3,4 ];
$expected = [
'1-2-3-4',
'2-1-3-4',
'3-1-2-4',
'1-3-2-4',
'2-3-1-4',
'3-2-1-4',
'4-2-1-3',
'2-4-1-3',
'1-4-2-3',
'4-1-2-3',
'2-1-4-3',
'1-2-4-3',
'1-3-4-2',
'3-1-4-2',
'4-1-3-2',
'1-4-3-2',
'3-4-1-2',
'4-3-1-2',
'4-3-2-1',
'3-4-2-1',
'2-4-3-1',
'4-2-3-1',
'3-2-4-1',
'2-3-4-1',
];
function mixture( $size, array &$collection ) {
$permutations = [];
$offset = $size - 1;
if ( 1 === $size ) {
$permutations[] = implode( '-', $collection );
return $permutations;
}
for ( $i = 0; $i < $offset; $i++ ) {
$permutations = array_merge( $permutations, mixture( $offset, $collection ) );
$j = ( 0 == $size % 2 ) ? $i : 0;
$tmp_el = $collection[ $offset ];
$collection[ $offset ] = $collection[ $j ];
$collection[ $j ] = $tmp_el;
}
$permutations = array_merge( $permutations, mixture( $offset, $collection ) );
return $permutations;
}
print_r($permutations = mixture( count($arr), $arr ));
if ($expected == $permutations) {
echo 'PASS'.PHP_EOL;
} else {
echo 'FAIL'.PHP_EOL;
echo 'missing: '.PHP_EOL;
print_r(array_diff($expected, array_unique($permutations)));
}
Related
I'm Getting some arrays from some wordpress custom fields:
$content = array(get_post_meta($postId, 'content'));
$media = array(get_post_meta($postId, 'media'));
$yt = array(get_post_meta($postId, 'youtube'));
I then need to have it printing in sequence, like:
media
content
LInk
Embed
And repeat the sequence for each value
media
content
LInk
Embed
For the sequence I'd use this:
echo '<ul>';
for ($i = 0; $i < count($all_array['media']); $i++) {
for ($j = 0; $j < count($all_array['content']); $j++) {
for ($k = 0; $k < count($all_array['youtube']); $k++) {
echo '<li>media->' . $all_array['media'][$i] . '</li>';
echo '<li>content->' . $all_array['content'][$j] . '</li>';
echo '<li>link->' . $all_array['link'][$k] . '</li>';
}
}
}
echo '</ul>';
But I'm doing something wrong with the merging of the 3 fields as if I do a var_dump before to run the for bit, like
echo '<pre>' . var_export($all_array, true) . '</pre>';
Then this is what I get and I cannot iterate as I wish:
array (
0 =>
array (
0 =>
array (
0 => '
brother
',
1 => '
Lorem
',
2 => '
End it
',
),
1 =>
array (
0 => '337',
1 => '339',
),
2 =>
array (
0 => 'https://www.youtube.com/watch?v=94q6fzbJUfg',
),
),
)
Literally the layout in html that I'm looking for is:
image
content
link
image
content
link
...
UPDATE
This how I am merging the arrays:
foreach ( $content as $idx => $val ) {
$all_array[] = [ $val, $media[$idx], $yt[$idx] ];
}
This is the associative array how it looks like:
Content:
array (
0 =>
array (
0 => '
brother
',
1 => '
Lorem
',
2 => '
End it
',
),
)
Media
array (
0 =>
array (
0 => '337',
1 => '339',
),
)
Youtube
array (
0 =>
array (
0 => 'https://www.youtube.com/watch?v=94q6fzbJUfg',
),
)
The way I've resolved it is first I calculate the tot. items within each array, then I get the array with max items and loop and add the items in sequence:
//GET CUSTOM FIELDS
$content = get_post_meta($post_to_edit->ID, 'content', false);
$media = get_post_meta($post_to_edit->ID, 'media', false);
$yt = get_post_meta($post_to_edit->ID, 'youtube', false);
$max = max(count($content), count($media), count($yt));
$combined = [];
//
// CREATE CUSTOM FIELDS UNIQUE ARRAY
for($i = 0; $i <= $max; $i++) {
if(isset($media[$i])) {
$combined[] = ["type" => "media", "value" => $media[$i]];
}
if(isset($content[$i])) {
$combined[] = ["type" => "content", "value" => $content[$i]];
}
if(isset($yt[$i])) {
$combined[] = ["type" => "youtube", "value" => $yt[$i]];
}
}
Finally I can loop:
foreach ($combined as $key => $val) {
if($val['type'] === "media") {
...
}
if($val['type'] === "content") {
...
You don't need to merge the arrays together. It will work fine in separate arrays. However, your for loops don't have the right logic. Try:
for ($i = 0; $i < count($media); $i++) {
for ($j = 0; $j < count($media[$i]); $j++) {
echo '<li>media->' . $media[$i][$j] . '</li>';
}
for ($j = 0; $j < count($content[$i]); $j++) {
echo '<li>content->' . $content[$i][$j] . '</li>';
}
for ($j = 0; $j < count($youtube[$i]); $j++) {
echo '<li>link->' . $youtube[$i][$j] . '</li>';
}
}
I have a calcultion based on items minus stock value (with some community help). If it hits zero then the next row will be touched.
$items = 45;
$stockRows = [40, 50, 60];
$newStock = function ($items, $stock) {
foreach ($stock as &$item) {
$delta = $item - $items;
$item = $delta > 0 ? $delta : 0;
$items = $delta < 0 ? abs($delta) : 0;
}
return $stock;
};
print_r($newStock($items, $stockRows));
Output
Array
(
[0] => 0
[1] => 45
[2] => 60
)
Now I want to add a row identifier so that I can update the database rows afterwards in a foreach and set the correct stock amount
$stockRows =
array(
array(
'id' => 1,
'amount' => 30
),
array(
'id' => 2,
'amount' => 40
),
array(
'id' => 3,
'amount' => 50
)
);
I cant get this to work. And if I get a output the first array result returns id 0.
Fixed it myself
$items = 45;
$ids = [1, 2, 3];
$stockRows = [40, 50, 60];
$newStock = function ($afschrijving, $stock, $ids) {
$i = 0;
foreach ($stock as &$item) {
$delta = $item - $afschrijving;
$item = array($id[$i++], $delta > 0 ? $delta : 0);
$afschrijving = $delta < 0 ? abs($delta) : 0;
}
return $stock;
};
print_r($newStock($items, $stockRows, $ids));
I am generating test data for use in my frontend and I want to generate ages. Currently I am generating age between 18 and 100 using rand(1,100) like this:
require_once 'vendor/autoload.php';
$faker = Faker\Factory::create();
$superstars = array("Adam Cole","Finn Balor","Pete Dunne","Jordan Devlin","Noam Dar");
$fan_favourite_superstar_name = $superstars[ mt_rand( 0, count($superstars) -1 ) ];
$cities = array("London","Manchester","Leeds","Bristol");
$fan_location = $cities[ mt_rand( 0, count($cities) -1 ) ];
$the_models = array("Iphone","Nokia","Huawei","Samsung");
$fan_phone_model = $the_models[ mt_rand( 0, count($the_models) -1 ) ];
$array = Array (
"0" => Array (
"id" => uniqid(),
"fan_favourite_superstar_name" => $fan_favourite_superstar_name,
"fan_location" => $fan_location,
"fan_phone_model" => $fan_phone_model,
"fan_name" => $faker->name,
"fan_age" => rand(18,100),
"fan_comments" => $faker->text,
"fan_picture" => rand(1,500),
"last_updated" => time() + rand(1,1000),
),
However, I would like my ages to repeat although not completely. Is there a weak randomness generator apart from rand that can ensure that the an ages generated randomly repeat themselves n times?.
Here is a function just to show my suggestion of solution:
function getAge($start = 18, $end = 100, $repeat = 20){
$result = null;
static $ages = array();
if ( empty($ages) ) {
for ($i= $start; $i <= $end; $i++) {
for($j = 0; $j < $repeat; $j++)
$ages[] = $i;
}
}
$index = rand(0, count($ages));
$result = $ages[ $index ];
unset($ages[ $index ]);
$ages = array_values($ages);
return $result;
}
I need a proper JSON file with "geo_langitude", "geo_latitude", "adress" & "url" values
I have wp database with post_meta "property" - "geo_langitude" "geo_latitude" & "address" in there.
my file is smth like that
<?php
function return_markers($count) {
$query = new WP_Query('post_type=property&posts_per_page=-1&orderby=menu_order&order=DESC&post_status=publish');
$array = array();
$i = 0;
for ($i = 0; $i< $count; $i++) {
$elem = array(
't' => 'string '.$i,
'x' => get_post_meta($post->ID,'geo_latitude',true),
'y' => get_post_meta($post->ID,'geo_longitude',true),
'z' => $i
);
$array[] = $elem;
}
echo json_encode($elem);
};
return_markers($i);
?>
It's my first time using JSON so I have troubles and I don't know where. =(
with random markers work perfectly:
<?php
function return_markers($count) {
$array = array ();
for ($i = 0; $i< $count; $i++) {
$elem = array(
't' => 'string '.$i,
'x' => 23 + (rand ( 0 , 10000 ) / 10000) * 5,
'y' => 56.2 + (rand ( 0 , 10000 ) / 10000) * 0.8,
'url' => '#map_redirect_'.$i,
'z' => $i
);
$array[] = $elem;
}
echo json_encode($array);
};
return_markers(23);
?>
Broadly speaking, I have a 2-dimensional array of the following format:
$elements = array( 0 => array('typeA', 'desc'),
1 => array('typeB', 'desc'),
2 => array('typeA', 'desc'),
n => array('typeC', 'desc'));
Where typeX can be 1 of 5 possibilities, and desc can be anything. The end goal is $elements sorted such that no two elements who share a typeX are ever adjacent. Here's my function:
function fixDbls($elems) {
$final = array();
$singles = array();
$doubles = array();
$lastelem = null;
foreach($elems as $elem) {
if(!$lastelem) { // set this the first time through
$lastelem = $elem[0];
$singles[] = $elem;
} else { //otherwise, sort!
if($lastelem == $elem[0]) {
$doubles[] = $elem;
} else {
$singles[] = $elem;
}
}
}
if ($doubles) {
// I suspect this is where it all goes wrong, I am awful at recursion!
$final = fixDbls(array_merge($singles, $doubles));
} else {
$final = $singles;
}
return $final;
}
If anyone can help me understand why this doesn't work (not just the code, but, where I've made a false assumption or where my thinking about this problem betrayed meāhelps makes this more generally useful to the public!) I'd be ever, ever so appreciative.
I've been thinking your problem over and I think I came up with a solution. Here's the
code:
<?php
function print_array( $s, $a )
{
echo $s.': { ';
foreach ( $a as $k => $aa ) {
echo $k.' => ';
if ( is_array($aa) ) {
echo '{ '.implode( ', ', $aa ).' }, ';
} else {
echo $aa.', ';
}
}
echo '}'.PHP_EOL;
}
function search_array( array $a, $k )
{
$found = false;
foreach ( $a as $kk => $aa ) {
if ( $aa[0] == $k ) {
$found = $kk;
break;
}
}
return $found;
}
$input = array(
array('typeA', 'desc'),
array('typeB', 'desc'),
array('typeA', 'desc'),
array('typeC', 'desc')
);
print_array( 'Initial input', $input );
$frequencies = array();
foreach ( $input as $e ) {
$frequencies[ $e[0] ] = array_key_exists( $e[0], $frequencies ) ? $frequencies[ $e[0] ] + 1 : 1;
}
arsort($frequencies);
print_array( 'Frequencies', $frequencies );
$tail = array_slice( $frequencies, 1 );
$maxFreq = current( $frequencies );
$orderedElems = array_keys( $frequencies );
$mostFreq = current( $orderedElems );
echo 'The most frecuent element is "'.$mostFreq.'"'.PHP_EOL;
if ( array_sum( $tail ) < $maxFreq - 1 ) {
die ('There\'s No possible solution'.PHP_EOL);
}
$ouput = array();
for ( $i = 0; $i < $maxFreq; $i++ ) {
$k = search_array( $input, $mostFreq);
$output[] = $input[ $k ];
unset( $input[ $k ] );
}
print_array( 'Input after removing "'.$mostFreq.'"', $input );
echo '-----'.PHP_EOL;
print_array( 'Before process, output', $output );
foreach ( $tail as $e => $f ) {
$i = 1;
echo 'Elem to place: "'.$e.'" ('.$f.' times)'.PHP_EOL;
while ( ( $k = search_array( $input, $e ) ) !== false ) {
echo '$i: '.$i.PHP_EOL;
$begin = array_slice( $output, 0, $i );
print_array( 'Begin', $begin );
$end = array_slice( $output, $i );
print_array( 'End', $end );
$output = array_merge( $begin, array( $input[$k] ), $end );
print_array( 'Output', $output );
$i+=2;
unset( $input[$k] );
echo PHP_EOL;
}
}
print_array( 'Final output', $output );
This time I just tried the example you put in the question. The end result was:
Final output: { 0 => { typeA, desc }, 1 => { typeB, desc }, 2 => { typeC, desc }, 3 => { typeA, desc }, }
I hope this version suits your needs.
I made it a function now. This should work, the best.
$elements = array(0 => array('typeA', 'desc'), 1 => array('typeA', 'desc'), 2 => array('typeB', 'desc'), 3 => array('typeC', 'desc'), 4 => array('typeC', 'desc'), 5 => array('typeB', 'desc'), 6 => array('typeB', 'desc'), 7 => array('typeD', 'desc'), 8 => array('typeD', 'desc'), 9 => array('typeA', 'desc'), 10 => array('typeA', 'desc'));
function sortDeep($ary){
foreach($ary as $a){
foreach($a as $i => $v){
if($i === 0)$typesArray[] = $v;
}
}
function notNextTo($a, $b){
if($a === $b){
return 1;
}
else{
return 0;
}
}
uasort($typesArray, 'notNextTo'); $ak = array_keys($typesArray);
foreach($ary as $i => $v){
$sorted[$i] = $ary[$ak[$i]];
}
return $sorted;
}
print_r(sortDeep($elements));