Loop through array with wildcard for element name - php

I am working a Rightmove BLM file and converting it into an array which is working fine.
However, the images are stored in sequential element nodes MEDIA_IMAGE_00, 01, 02 etc..
I am wondering if someone can advise me the best way to loop though those sequential elements using a wildcard or similar MEDIA_IMAGE_* for example.
Example of struture:
[MEDIA_IMAGE_00] => 003436_RX78401_IMG_00.jpg
[MEDIA_IMAGE_TEXT_00] =>
[MEDIA_IMAGE_01] => 003436_RX78401_IMG_01.jpg
[MEDIA_IMAGE_TEXT_01] =>
[MEDIA_IMAGE_02] => 003436_RX78401_IMG_02.jpg
[MEDIA_IMAGE_TEXT_02] =>
[MEDIA_IMAGE_03] => 003436_RX78401_IMG_03.jpg
Many Thanks!

The easiest solution might be:
foreach($array as $key=>$image)
{
if(str_contains($key, 'MEDIA_IMAGE_'))
{
//$image is your filename for the current image
}
}
But you can use RegEx instead.
In this case you just change the condition of the if to something like:
preg_match('/MEDIA_IMAGE_\d\d/', $key) === 1

You can use array_filter() in combination with an own filter-function.
Example
$inputArray['MEDIA_IMAGE_00'] = '003436_RX78401_IMG_00.jpg';
$inputArray['MEDIA_IMAGE_TEXT_00'] = '';
$inputArray['MEDIA_IMAGE_01'] = '003436_RX78401_IMG_01.jpg';
$inputArray['MEDIA_IMAGE_TEXT_01'] = '';
$inputArray['MEDIA_IMAGE_02'] = '003436_RX78401_IMG_02.jpg';
$inputArray['MEDIA_IMAGE_TEXT_02'] = '';
$inputArray['MEDIA_IMAGE_03'] = '003436_RX78401_IMG_03.jpg';
var_dump($inputArray);
/*
array(7) {
["MEDIA_IMAGE_00"]=>
string(25) "003436_RX78401_IMG_00.jpg"
["MEDIA_IMAGE_TEXT_00"]=>
string(0) ""
["MEDIA_IMAGE_01"]=>
string(25) "003436_RX78401_IMG_01.jpg"
["MEDIA_IMAGE_TEXT_01"]=>
string(0) ""
["MEDIA_IMAGE_02"]=>
string(25) "003436_RX78401_IMG_02.jpg"
["MEDIA_IMAGE_TEXT_02"]=>
string(0) ""
["MEDIA_IMAGE_03"]=>
string(25) "003436_RX78401_IMG_03.jpg"
}
*/
$inputArray = array_filter($inputArray, function($key) {
return preg_match('/MEDIA_IMAGE_\d\d/', $key) === 1;
}, ARRAY_FILTER_USE_KEY);
var_dump($inputArray);
/*
array(4) {
["MEDIA_IMAGE_00"]=>
string(25) "003436_RX78401_IMG_00.jpg"
["MEDIA_IMAGE_01"]=>
string(25) "003436_RX78401_IMG_01.jpg"
["MEDIA_IMAGE_02"]=>
string(25) "003436_RX78401_IMG_02.jpg"
["MEDIA_IMAGE_03"]=>
string(25) "003436_RX78401_IMG_03.jpg"
}
*/
If you just want to filter out empty values, you can even use filter_array() without any custom function. See the documentation for more information.
Documentation
array_filter() in php documentation.

Related

Create specific patterns for a numeric range from given start and end numbers

I want to create a function which generates specific patterns to describe a numeric range between two given numbers. The function accepts two parameters: $startNumber and $endNumber. It should return an array of pattern strings. The best way to describe it is with examples:
myfunction(00000, 99999) = array('*');
myfunction(10000, 29999) = array('1*', '2*');
myfunction(68000, 68999) = array('68*');
myfunction(0004000, 0008999) = array('0004*', '0005*', '0006*', '0007*', '0008*');
myfunction(5570000, 5659999) = array('557*', '558*', '559*', '560*', '561*', '562*', '563*', '564*', '565*');
myfunction(3760000, 5259999) = array('376*', '377*', '378*', '379*', '38*', '39*', '4*', '50*', '51*', '520*', '521*', '522*', '523*', '524*', '525*');
myfunction(12345, 45678) = array('12345*', '12346*', '12347*', '12348*', '12349*', '1235*', '1236*', '1237*', '1238*', '1239*', '124*', '125*', '126*', '127*', '128*', '129*', '13*', '14*', '15*', '16*', '17*', '18*', '19*', '2*', '3*', '40*', '41*', '42*', '43*', '44*', '450*', '451*', '452*', '453*', '454*', '455*', '4560*', '4561*', '4562*', '4563*', '4564*', '4565*', '4566*', '45670*', '45671*', '45672*', '45673*', '45674*', '45675*', '45676*', '45677*', '45678*');
myfunction(000000, 399099) = array('0*', '1*', '2*', '30*', '31*', '32*', '33*', '34*', '35*', '36*', '37*', '38*', '390*', '391*', '392*', '393*', '394*', '395*', '396*', '397*', '398*', '3990*');
Since some parts of your issue are not clear,
I'll get closer to the first need you are claiming...
For the range
You don't need to recode the existing ;-)
Look for range() native function, can already do that for you:
function myfunction($start, $end)
{
$r = range($start, $end);
return array_map(function($n)
{
return $n.'*';
}, $r);
}
var_dump(myfunction(34, 39));
// will output:
array(6) {
[0]=>
string(3) "34*"
[1]=>
string(3) "35*"
[2]=>
string(3) "36*"
[3]=>
string(3) "37*"
[4]=>
string(3) "38*"
[5]=>
string(3) "39*"
}

Changing values of multidimensional array php

Its my first time working with multidimensional arrays in php. I need to change the second number in each sub array.
What I want is to check if the Id in the array matches the Id from the database. When the two match I want to change the 2nd entry in the sub array by adding a number to it. If the Id from the query does not match anything in the list I want a new sub array to be pushed to the end of the array with the values of Id and points_description.
Also, if its helpful, my program right now does find the matches. The only thing is, it does not update the 2D array.
$array = array(array());
while ($row_description = mysqli_fetch_array($query_description)) {
$check = 1;
$is_match = 0;
foreach ($array as $i) {
foreach ($i as $value) {
if ($check == 1) {
if ($row_description['Id'] == $value) {
//$array[$i] += $points_description;
$is_match = 1;
}
}
$check++;
$check %= 2; //toggle between check and points
}
}
if ($is_match == 0) {
array_push($array, array($row_description['Id'], $points_description));
}
}
I feel like Im doing this so wrong. I just want to go through my 2D array and change every second value. The expected output should be a print out of all the Ids and their corresponding point value
I hope this is helpful enough.
Example: $row_description['Id'] = 2 and $array = array(array(2,1), array(5,1) , array(6,1))
output should be $array = array(array(2,4), array(5,1) , array(6,1))
if $row_description['Id'] = 3 and $array = array(array(2,1), array(5,1) , array(6,1))
output should be $array = array(array(2,4), array(5,1) , array(6,1),array(3,3))
By default PHP will copy an array when you use it in a foreach.
To prevent PHP from creating this copy you need to use to reference the value with &
Simple example :
<?php
$arrFoo = [1, 2, 3, 4, 5,];
$arrBar = [3, 6, 9,];
Default PHP behavior : Make a copy
foreach($arrFoo as $value_foo) {
foreach($arrBar as $value_bar) {
$value_foo *= $value_bar;
}
}
var_dump($arrFoo);
/* Output :
array(5) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
[3]=>
int(4)
[4]=>
int(5)
}
*/
ByReference : Don't create the copy :
foreach($arrFoo as &$value_foo) {
foreach($arrBar as $value_bar) {
$value_foo *= $value_bar;
}
}
var_dump($arrFoo);
/* Output :
array(5) {
[0]=>
int(162)
[1]=>
int(324)
[2]=>
int(486)
[3]=>
int(648)
[4]=>
&int(810)
}
*/

How do I check to see if array slot is empty?

In the example below $list is an array created by user input earlier in the code, and some slots the user has input nothing. I want to skip the empty items, so the commas aren't created in the output.
$list = array("first", "second", "", "", "fifth", "sixth", "", "");
foreach ($list as $each){$places .= $each . ",";}
results
first,second,,,fifth,sixth,,,
result I want
first,second,fifth,sixth
Got a solution. It looks like this:
$list = array_filter($list);
$places .= implode (",",$list);
To ignore the empty values, you can use
$list = array_filter($list);
Results
Array
(
[0] => first
[1] => second
[4] => fifth
[5] => sixth
)
Source: Mark
array_filter, when passed no second parameter, will remove any empty entries. From there you can proceed as normal:
foreach (array_filter($list) as $each){
$places .= $each . ',';
}
Though you can also use implode if you're just turning it in to a CSV:
$places .= implode(',', array_filter($list));
Side Note Though in this case array_filter may work, it is worth noting that this removes entries that result in a "falsy" result. That is to say:
$list = array_filter(array('foo','0','false',''));
// Result:
// array(2) {
// [0]=>
// string(3) "foo"
// [2]=>
// string(5) "false"
// }
So be careful. If the user could potentially be entering in numbers, I would stick with comparing empty. Alternatively you can use the second parameter of array_filter to make it more explicit:
function nonEmptyEntries($e)
{
return ((string)$e) !== '';
}
$list = array_filter($list, 'nonEmptyEntries');
// result:
//array(3) {
// [0]=>
// string(3) "foo"
// [1]=>
// string(1) "0"
// [2]=>
// string(5) "false"
//}
(Note that the 0 entry is kept, which differs from a blanket array_filter)

Random But Unique Pairings, with Conditions

I need some help/direction in setting up a PHP script to randomly pair up items in an array.
The items should be randomly paired up each time.
The items should not match themselves ( item1-1 should not pair up with item1-1 )
Most of the items have a mate (ie. item1-1 and item1-2). The items should not be paired with their mate.
I've been playing around with the second script in this post but, I haven't been able to make any progress. Any help is appreciated.
Very simple approach, but hopefully helpful to you:
(mates, if grouped in an array (e.g. array('a1', 'a2')), will not be paired.)
function matchUp($array) {
$result = array();
while($el = array_pop($array)) {
shuffle($array);
if (sizeof($array) > 0) {
$candidate = array_pop($array);
$result[] = array(
array_pop($el),
array_pop($candidate)
);
if (sizeof($el) > 0) {
$array[] = $el;
}
if (sizeof($candidate) > 0) {
$array[] = $candidate;
}
}
else {
$result[] = array(array_pop($el));
}
}
return $result;
}
$array = array(
array('a1', 'a2'),
array('b1', 'b2'),
array('c1'),
array('d1'),
array('e1', 'e2'),
array('f1'),
array('g1', 'g2'),
);
Update:
foreach(matchUp($array) as $pair) {
list($a, $b) = $pair + array(null, null);
echo '<div style="border: solid 1px #000000;">' . $a . ' + ' . $b . '</div>';
}
With the randomness, there is no guarantee that a full correct solution will be reached.
Certain problem sets are more likely to be solved than others. Some will be impossible.
You can configure how many times it will try to achieve a good solution. After the specified number of tries it will return the best solution it could find.
function pairUp (array $subjectArray) {
// Config options
$tries = 50;
// Variables
$bestPaired = array();
$bestUnpaired = array();
for($try = 1; $try <= 50; $try++) {
$paired = array();
$unpaired = array();
$toBePaired = $subjectArray;
foreach($subjectArray as $subjectIndex => $subjectValue) {
// Create array without $thisValue anywhere, from the unpaired items
$cleanArray = array();
foreach($toBePaired as $index => $value) {
if($value != $subjectValue) {
array_push($cleanArray, array(
'index' => $index,
'value' => $value
));
}
}
sort($cleanArray); // reset indexes in array
// See if we have any different values left to match
if(count($cleanArray) == 0) {
array_push($unpaired, $subjectValue);
continue;
}
// Get a random item from the clean array
$randomIndex = rand(0,count($cleanArray)-1);
// Store this pair
$paired[$subjectIndex] = $subjectValue . '-' . $cleanArray[$randomIndex]['value'];
// This item has been paired, remove it from unpairedItems
unset($toBePaired[$cleanArray[$randomIndex]['index']]);
sort($toBePaired);
}
// Decide if this is our best try
if(count($paired) > count($bestPaired)) {
$bestPaired = $paired;
$bestUnpaired = $unpaired;
}
// If we had no failures, this was a perfect try - finish
if(count($unpaired) == 0) { $break; }
}
// We're done, send our array of pairs back.
return array(
'paired' => $bestPaired,
'unpaired' => $bestUnpaired
);
}
var_dump(pairUp(array('a','b','c','d','e','a','b','c','d','e')));
/*
Example output:
array(2) {
["paired"]=>
array(10) {
[0]=>
string(3) "a-b"
[1]=>
string(3) "b-c"
[2]=>
string(3) "c-d"
[3]=>
string(3) "d-e"
[4]=>
string(3) "e-a"
[5]=>
string(3) "a-b"
[6]=>
string(3) "b-e"
[7]=>
string(3) "c-d"
[8]=>
string(3) "d-c"
[9]=>
string(3) "e-a"
}
["unpaired"]=>
array(0) {
}
}
*/
Case 1: if all elements had a mate
If all elements had a mate, the following solution would work, although I don't know if it would be perfectly random (as in, all possible outputs having the same probability):
Shuffle the list of elements, keeping mates together
original list = (a1,a2),(b1,b2),(c1,c2),(d1,d2)
shuffled = (c1,c2),(d1,d2),(a1,a2),(b1,b2)
Shift the second mate to the right. The matches have been formed.
shifted = (c1,b2),(d1,c2),(a1,d2),(b1,a2)
(Edit1: if applied exactly as described, there is no way a1 ends up matched with b1. So, before shifting, you may want to throw a coin for each pair of mates to decide whether they should change their order or not.)
Case 2: if only some elements have a mate
Since in your question only some elements will have a mate, I guess one could come up with the following:
Arbitrarily pair up those elements who don't have a mate. There should be an even number of such elements. Otherwise, the total number of elements would be odd, so no matching could be done in the first place.
original list = (a1,a2),(b1,b2),c1,d1,e1,f1 // c1,d1,e1 and f1 don't have mates
list2 = (a1,a2),(b1,b2),(c1,d1),(e1,f1) // pair them up
Shuffle and shift as in case 1 to form the matches.
shuffled = (e1,f1),(a1,a2),(c1,d1),(b1,b2)
shifted = (e1,b2),(a1,f1),(c1,a2),(b1,d1)
Again, I don't know if this is perfectly random, but I think it should work.
(Edit2: simplified the solution)
(Edit3: if the total number of elements is odd, someone will be left without a match, so pick an element randomly at the beginning to leave it out and then apply the algorithm above).

php pushing pattern from array1 to array2

I have an array that looks something like this
array(7) {
[0]=> "hello,pat1"
[1]=> "hello,pat1"
[2]=> "test,pat2"
[3]=> "test,pat2"
[4]=> "foo,pat3"
[5]=> "foo,pat3"
[6]=> "foo,pat3"
....
}
I would like to push it into another array so the output of the array2 is as follow:
array(7) {
[0]=> "hello,pat1"
[1]=> "test,pat2"
[2]=> "foo,pat3"
[3]=> "foo,pat3"
[4]=> "foo,pat3"
[5]=> "hello,pat1"
[6]=> "test,pat2"
.....
}
What I want is to push them in the following pattern: 1 "pat1" 1 "pat2" and 3 "pat3", and repeat this pattern every 5 elements.
while ( !empty( $array1 ) )
$a = explode(",",$array1[$i]);
if($a[1]=='pat1' &&)
push && unset
elseif($a[1]=='pat2' &&)
push && unset
elseif($a[1]=='pat3' and < 5)
push && unset and reset pattern counter
}
What would be a good way of doing this?
Any idea will be appreciate it.
Time for some fun with the iterators of the Standard PHP Library :-)
<?php
$array1 = array (
"hello1,pat1", "hello2,pat1", "hello3,pat1",
"test1,pat2", "test2,pat2",
"foo1,pat3", "foo2,pat3", "foo3,pat3",
"foo4,pat3", "foo5,pat3", "foo6,pat3"
);
// "group by" patN
$foo = array();
foreach($array1 as $a) {
// feel free to complain about the # here ...to somebody else
#$foo[ strrchr($a, ',') ][] = $a;
}
// split pat3 into chunks of 3
$foo[',pat3'] = array_chunk($foo[',pat3'], 3);
// add all "groups" to a MultipleIterator
$mi = new MultipleIterator(MultipleIterator::MIT_NEED_ANY);
foreach($foo as $x) {
$mi->attachIterator( new ArrayIterator($x) );
}
// each call to $mi->current() will return an array
// with the current items of all registered iterators
foreach ($mi as $x) {
// "flatten" the nested arrays
foreach( new RecursiveIteratorIterator(new RecursiveArrayIterator($x)) as $e) {
echo $e, "\n";
}
echo "----\n";
}
I think I'd set respective counters with respective incrementation. Since php will cast float keys to integers, you can just increment the ,pat3 items with .33 instead of 1. Then, to flatten the result, just use array_merge() with the splat operator.
Code: (Demo)
$array = [
"hello1,pat1",
"hello2,pat1",
"test3,pat2",
"test4,pat2",
"foo5,pat3",
"foo6,pat3",
"foo7,pat3",
];
$counters = [',pat1' => 0, ',pat2' => 0, ',pat3' => 0];
foreach ($array as $value) {
$end = strrchr($value, ',');
$groups[$counters[$end]][] = $value;
$counters[$end] += ($end === ',pat3' ? .33 : 1);
}
var_export(array_merge(...$groups));
Output:
array (
0 => 'hello1,pat1',
1 => 'test3,pat2',
2 => 'foo5,pat3',
3 => 'foo6,pat3',
4 => 'foo7,pat3',
5 => 'hello2,pat1',
6 => 'test4,pat2',
)

Categories