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)
Related
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.
I want to get file name (with extension .png or .jpg or .gif) from the string given below :
{src:"brand.png", id:"brand"},
{src:"centpourcent.png", id:"centpourcent"},
{src:"corsa.png", id:"corsa"},
{src:"cta.png", id:"cta"},
{src:"neons.png", id:"neons"}
From the above string i want to get output like :
[ brand.png, centpourcent.png, corsa.png, cta.png, neons.png ] // Or may be as string output
I tried below code but it didnt work for me:
substr($images, strpos($images, "src:") + 5);
Im getting output as
brand.png", id:"brand"},
{src:"centpourcent.png", id:"centpourcent"},
{src:"corsa.png", id:"corsa"},
{src:"cta.png", id:"cta"},
{src:"neons.png", id:"neons"}
<?php
$string = '{src:"brand.png", id:"brand"},
{src:"centpourcent.png", id:"centpourcent"},
{src:"corsa.png", id:"corsa"},
{src:"cta.png", id:"cta"},
{src:"neons.png", id:"neons"}';
// Here I replace the src with "src" and id with "id"
$string = str_replace(['src', 'id'], ['"src"', '"id"'], $string);
// Then I wrap all the string in brackets to convert the string to valid JSON string.
$json = '[' . $string . ']';
// Finally I decode the JSON string into a PHP array.
$data = json_decode($json);
// Here I am going to save the images names.
$images = [];
// Here I itterate the json body entries and I push into the $images array
// the image name
foreach($data as $entry) {
array_push($images, $entry->src);
}
// And here I just print it out, to make sure the output is the following:
print_r($images);
// OUTPUT:
// Array
// (
// [0] => brand.png
// [1] => centpourcent.png
// [2] => corsa.png
// [3] => cta.png
// [4] => neons.png
// )
You can preg_match_all() use to get all file names.
$str = '{src:"brand.png", id:"brand"},
{src:"centpourcent.png", id:"centpourcent"},
{src:"corsa.png", id:"corsa"},
{src:"cta.png", id:"cta"},
{src:"neons.png", id:"neons"}';
$r = preg_match_all('~(?:src:")([^"]+)(?:")~',$str,$match);
var_dump($match[1])
Output:
array(5) {
[0]=>
string(9) "brand.png"
[1]=>
string(16) "centpourcent.png"
[2]=>
string(9) "corsa.png"
[3]=>
string(7) "cta.png"
[4]=>
string(9) "neons.png"
}
Added:
If a valid JSON string is to be generated from the specified string, this can also be done with a regular expression.
The algorithm also works without changes with keys other than 'src' and 'id'.
$jsonStr = '['.preg_replace('~\w+(?=:)~','"$0"', $str).']';
Or you can just use Regex:
(?<=")[^\\\/\:\*\?\"\<\>\|]+\.(?:png|jpg|gif)(?=")
I have an array named $initValues, which contains strings or numeric values and using a foreach loop I want to transfer the values to the $values array and the type of each value to $types.
Code:
$initValues = ["1-2", "2-1"];
$values = [];
$types = [];
foreach ($initValues as $value) {
$values[] = &$value; # by reference.
$types[] = gettype($value);
}
As you can see in the above code, I'm inserting the value by reference in $values, which is required by a function used later on, so that can't be changed. When I execute the above code and show the result using var_dump($values), I get the following:
array(2) { [0]=> &string(3) "2-1" [1]=> &string(3) "2-1" }
The problem with the above result is that essentially both elements of my $values array are the last element of $initValues and not both as in the desired result, which is:
array(2) { [0]=> &string(3) "1-2" [1]=> &string(3) "2-1" }
If I enter each value by value into the array the result is correct, but I'm facing a problem later on, so that's not an option. How can I modify my code, in order to produce the desired result?
Use an index in your foreach loop.
This should work:
$initValues = ["1-2", "2-1"];
$values = [];
$types = [];
foreach ($initValues as $ix=>$value) {
$values[] = &$initValues[$ix];
$types[] = gettype($value);
}
var_dump($values);
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).
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',
)