I'm trying two combine two arrays based on the values names.
Here what I'm trying to do :
$array1 = ("fifa21","pes21","halflife2","carma2");
$array2 = ("fifa21_cover","pes21_cover","halflife2_cover");
I want to loop through both arrays and if value from array1 match value from array 2 it will list both values like this :
fifa21 - fifa21_cover
pes21 - pes21_cover
halflife2 - halflife2_cover
carma2 - default_cover
if not find anything in the array2, a default cover will be used.
Note: the arrays will be filled dynamically based in a scanDir (two different folders search) and the arrays can be sorted differently than shown in the example above.
This code will loop through array1 and check to see if the item cover exists in array2, if it does then it will echo out in the format you wanted.
$array1 = array("fifa21","pes21","halflife2","carma2");
$array2 = array("fifa21_cover","pes21_cover","halflife2_cover");
foreach ($array1 as $item) {
if (in_array($item."_cover", $array2)) {
echo "<p>".$item." - ".$item."_cover</p>\n";
} else {
// use default cover...
}
}
(because it is lunch time and I need to write some code)
Given two arrays:
$array1 = ["fifa21", "pes21", "halflife2", "carma2"];
$array2 = ["fifa21_cover", "pes21_cover", "halflife2_cover"];
A function such as this can walk through and look for items that start with those values:
function merge_arrays(array $array1, array $array2): array
{
$output = [];
array_walk(
$array1,
static function ($key) use ($array2, &$output) {
$items = array_filter($array2, static fn($f) => 0 === mb_strpos($f, $key));
if (count($items) === 1) {
$output[$key] = reset($items);
return;
}
if (count($items) === 0) {
$output[$key] = 'default_cover';
return;
}
throw new RuntimeException('More than one item found starting with key ' . $key);
}
);
return $output;
}
When called as:
print_r(merge_arrays($array1, $array2));
It will output:
(
[fifa21] => fifa21_cover
[pes21] => pes21_cover
[halflife2] => halflife2_cover
[carma2] => default_cover
)
For your use-case, it might be overly complicated when compared to a for loop, but it does the job.
Another version that more-blindly assumes only a one-to-one match could use the ?? operator for a null check, although I wouldn't recommend this. The more terse and compact that code looks, the more I find that it is usually very hard to reason about, especially in the future:
function merge_arrays(array $array1, array $array2): array
{
$output = [];
array_walk(
$array1,
static function ($key) use ($array2, &$output) {
$output[$key] = array_filter($array2, static fn($f) => 0 === mb_strpos($f, $key))[0] ?? 'default_cover';
}
);
return $output;
}
All code snipping provided works, however if the array values have extension it always assumes the default cover. I can figure it how using my code by removing the extension for compare purpose, and then I add it back.
Inside my loop I use this :
$keyvaluetemp = substr($keyvalue, 0, strrpos($keyvalue, "."));
the above it inside my first ForEach (where I check the first array), and then in the covers array I remove the "_cover" by nothing :
$keyvalue2temp = (str_replace("_cover", "",$keyvalue2));
then I use the following code inside the second ForEach to add the data to a DB:
// if fantart match the game file name so we associate it to the game and save to the DB
if ( stripos ( $keyvalue2temp , $keyvaluetemp ) !== FALSE )
{
$sql = "UPDATE listgames SET FanArt='$keyvalue2' WHERE Name='$keyvalue'";
$con->exec($sql);
}
// if fanart is empty we add a default picture
$checkifempty = "SELECT `FanArt` FROM `listgames` WHERE `Name` = '$keyvalue'";
$runsql = $con->query($checkifempty);
$row = $runsql->fetch(PDO::FETCH_ASSOC);
$fanartkey = $row['FanArt'];
if($fanartkey == '')
{
$sql = "UPDATE listgames SET FanArt='nopic.JPG' WHERE Name='$keyvalue'";
$con->exec($sql);
}
Later in my code I print the results from the DB. I don't know if this is the best approach, however it does exactly what I want :)
Related
In $data I have the following values:
Result
[{"id":2,"author":"example#mail.com","id_orders":502},
{"id":2,"author":"example#mail.com","id_orders":503},
{"id":2,"author":"example#mail.com","id_orders":505},
{"id":3,"author":"second-example#mail.com","id_orders":502},
{"id":3,"author":"second-example#mail.com","id_orders":503},
{"id":3,"author":"second-example#mail.com","id_orders":505},
{"id":4,"author":"third-example#mail.com","id_orders":502},
{"id":4,"author":"third-example#mail.com","id_orders":503},
{"id":4,"author":"third-example#mail.com","id_orders":505}]
I want unique results for id and id_orders. I want 3 out of these 9 results. I have tried this, but it helps on one id_orders condition.
PHP code
$result = json_decode($data, true);
$unique_array = [];
foreach($result as $element) {
$hash = $element['id_orders'];
$unique_array[$hash] = $element;
}
$data = array_values($unique_array);
Do you know how it can be different to make it work for two?
You can do it by keeping track of the values that were already used. Disclaimer: this solution will only produce a clear result for cases where the number of unique values for both criteria is the same.
$uniqueArray = [];
$usedValues = [
'id' => [],
'id_orders' => [],
];
foreach ($result as $element) {
if (!in_array($element['id'], $usedValues['id']) && !in_array($element['id_orders'], $usedValues['id_orders'])) {
$uniqueArray[] = $element;
$usedValues['id'][] = $element['id'];
$usedValues['id_orders'][] = $element['id_orders'];
}
}
Basically, what's happening here is that we're using $usedValues to store all the unique values we've already used and comparing against it using in_array. When we iterate through the objects, any object with an id or id_orders that has already been used will be skipped. The pairings will be done in order of appearance in the array.
I've gone an extra mile to try and make this code a bit more generic:
* Finds elements with a unique combination of values under given keys.
*
* Assumes all elements in the array are arrays themselves and that the
* subarrays have the same structure. Assumes subarray elements are not
* objects (uses strict comparison).
*/
function uniqueCombination(array $arrayToFilter, array $keysToFilterOn): array
{
if (empty($arrayToFilter) || empty($keysToFilterOn)) {
throw new \InvalidArgumentException(
'Parameters of uniqueCombination must not be empty arrays'
);
}
// get the keys from the first element; others are assumed to be the same
$keysOfElements = array_keys(reset($arrayToFilter));
$keysPresentInBoth = array_intersect($keysToFilterOn, $keysOfElements);
// no point in running the algorithm if none of the keys are
// actually found in our array elements
if (empty($keysPresentInBoth)) {
return [];
}
$result = [];
$usedValues = array_combine(
$keysPresentInBoth,
array_fill(0, count($keysPresentInBoth), [])
);
foreach ($arrayToFilter as $element) {
if (!isAlreadyUsed($usedValues, $element)) {
$result[] = $element;
foreach ($keysPresentInBoth as $keyToUse) {
$usedValues[$keyToUse][] = $element[$keyToUse];
}
}
}
return $result;
}
function isAlreadyUsed(array $usedValues, array $element): bool
{
foreach ($usedValues as $usedKey => $usedValue) {
if (in_array($element[$usedKey], $usedValue)) {
return true;
}
}
return false;
}
In its core, this is the same algorithm, but made dynamic. It allows a variable number of keys to filter on (that's why they're passed separately as an argument), so the $usedValues array is created dynamically (using the first element's keys as its own keys, filled with empty arrays) and all the keys must be compared in loops (hence the separate function to check if an element's value had already been used).
It could probably be tweaked here or there as I haven't tested it thoroughly, but should provide satisfactory results for most structures.
I would like to check all keys of a global GET array and do something, if it contains keys, other than some whitelisted ones from an array.
Let's say the current url is:
.../index.php?randomekey1=valueX&randomkey2=valueY&acceptedkey1=valueZ&randomkey3=valueA&acceptedkey2=valueB
Just for better visualization:
These GET parameters are all available in the global GET variable which looks something like this:
$GET = array(
"randomekey1" => "valueX",
"randomkey2" => "valueY",
"acceptedkey1" => "valueZ",
"randomkey3" => "valueA",
"acceptedkey2" => "valueB"
);
The keys I accept and want to let pass, I put into an array too:
$whitelist = array(
"acceptedkey1",
"acceptedkey2",
"acceptedkey3",
);
Now I want to check whether $GET contains any key other than the whitelisted. So in the URL example from above it should return "true", because there are keys in the $GET array which aren't in the whitelist.
Not only the existence of such an unknown (none whitelisted) key should trigger a true, but please also its emptyness!
Another example would be the following url:
.../index.php?acceptedkey1=valueZ&acceptedkey3=valueB
This should return false, because no other key other than the ones in the whitelist were found.
Unfortunately I was not able to find any modification of the in_array function or array_search which would fit these requirements, because as far as I know these functions are only looking for something specific, whereas in my requirements I am also looking for something specific (the whitelist keys), but at the same tme I have to check if some unknown keys exist.
Thank you.
It seems you want to determine whether an array contains keys that don't exist in a whitelist.
One way to find the difference between arrays is to use array_diff():
array_diff ( array $array1 , array $array2 [, array $... ] ) : array
Returns an array containing all the entries from array1 that are not present in any of the other arrays.
So, it can be used to return all keys from the URL that are not present in the whitelist:
$extrasExist = !empty( array_diff( array_keys($GET), $whitelist ) );
var_dump($extrasExist);
Here's a demonstration:
$get1 = array(
"randomekey1" => "valueX",
"randomkey2" => "valueY",
"acceptedkey1" => "valueZ",
"randomkey3" => "valueA",
"acceptedkey2" => "valueB"
);
$get2 = array(
"acceptedkey1" => "valueZ",
"acceptedkey2" => "valueB"
);
$whitelist = array(
"acceptedkey1",
"acceptedkey2",
"acceptedkey3"
);
$extrasExist = !empty(array_diff(array_keys($get1),$whitelist));
var_dump($extrasExist);
$extrasExist = !empty(array_diff(array_keys($get2),$whitelist));
var_dump($extrasExist);
bool(true)
bool(false)
Everything in PHP doesn't have to be all "lets find function that does exactly what I'm looking for". Just do a simple foreach loop, which can accomplish what you're looking for:
function clear_filter() {
$whitelist = array( "project", "table_name", "filterDates", );
foreach ($_GET as $gkey => $gval) {
if (!in_array($gkey, $whitelist)) {
return false;
}
}
return true;
}
You can also write it more simply, with one foreach loop like below:
function isValid() {
// Copy the array
$temp = $_GET;
// Loop through the array, and remove any whitelisted elements
foreach ($whitelist as $wkey) {
unset($temp[$wkey]);
}
// If count($temp) > 0, there are non whitelisted entries in the array.
return count($temp) === 0;
}
You can use the following function.
$check = checkWhitliest( $_GET, $whitelist ) );
var_dump ($check );
You can call the above function as
function checkWhitliest( $array, $whitelist ) {
$allKeys = array_keys ( $array); //Get all Keys from the array.
$diff = array_diff( $allKeys, $whitelist); //Get the values which are not in whitelist.
if( count ( $diff ) > 0 ) { //If the count is greater than 0, then there are certain extra kesy in $_GET
return true;
}
return false;
}
There are only two techniques that I would recommend for this task and both make key comparisons for performance reasons. Using array_diff() or in_array() will always be slower than array_diff_key() and isset(), respectively, because of how PHP treats arrays as hash maps.
If you don't mind iterating the entire $GET array (because its data is relatively small), then you can concisely flip the whitelist array and check for any key differences.
var_export(
(bool)array_diff_key($GET, array_flip($whitelist))
);
If performance is more important than code brevity, then you should craft a technique that uses a conditional break or return as soon as a non-whitelisted key is encountered -- this avoids doing pointless iterations after the outcome is decided.
$hasNotWhitelisted = false;
$lookup = array_flip($whitelist);
foreach ($GET as $key => $value) {
if (isset($lookup[$key])) {
$hasNotWhitelisted = true;
break;
}
}
var_export($hasNotWhitelisted);
Or
function hasNotWhitelisted($array, $whitelist): bool {
$lookup = array_flip($whitelist);
foreach ($array as $key => $value) {
if (isset($lookup[$key])) {
return true;
}
}
return false;
}
var_export(hasNotWhitelisted($GET, $whitelist));
All of the above techniques deliver a true result for the sample data. Demo of all three snippets.
Have a problem with checking array inside of large array of objects. For example I have
$arr1 = array("a"=>12,"b"=5,"c"=>16);
and I need to check if this array exists inside array like this:
$arr2 = array( array( "a"=>12,"b"=5,"c"=>16),
array("d"=>1,"g"=5,"c"=>16),
array("a"=>12,"c"=5,"e"=>3) );
I have tried in_array(), and it works, but takes a lot of time if I have large $arr2.
Thank you in advance.
P.S. works with PHP 5.6
Instead of your current $arr structure, you'd better have an associative array, where the keys uniquely identify the value.
If you need to search that array several times, you might still save time if you would spend some time to create such associative array from your existing array:
$arr2 = array(
array( "a"=>12,"b"=>5,"c"=>16),
array("d"=>1,"g"=>5,"c"=>16),
array("a"=>12,"c"=>5,"e"=>3)
);
// use key/value pairs, with as key the JSON-encoding of the value
// Note: this will take some time for very large arrays:
foreach ($arr2 as $sub) {
ksort($sub); // need to sort the keys to make sure we can find a match when needed
$hash[json_encode($sub)] = $sub;
}
// function to see whether the value is in the array: this will be fast!
function inHash($hash, $sub) {
ksort($sub);
return isset($hash[json_encode($sub)]);
}
// test
if (inHash($hash, array("d"=>1,"g"=>5,"c"=>16))) {
echo "found";
} else {
echo "not found";
}
Of course, if you could create the original immediately with such keys, then you don't have the overhead of creating it afterwards.
#D.Kurapin simply try with == or === operator(according to you) with foreach() like below:
<?php
$arr1 = array("a"=>12,"b"=>5,"c"=>16);
$arr2 = array( array( "a"=>12,"b"=>5,"c"=>16),
array("d"=>1,"g"=>5,"c"=>16),
array("a"=>12,"c"=>5,"e"=>3) );
$isExist = false;
foreach ($arr2 as $key => $value) {
if($value === $arr1){
$isExist = true;
break;
}
}
if($isExist){
echo "yes found in the array";
}
else{
echo "sorry did not find in the array";
}
$list = array(
[0]=> array(
[name]=>'James'
[group]=>''
)
[1]=> array(
[name]=>'Bobby'
[group]=>''
)
)
I am looking to update the item 'group' where the name is 'Bobby'. I am looking for a solution with the two following formats. Thank you in advance for your replies. Cheers. Marc.
array_push($list, ???)
and
$list[] ??? = someting
As far as I know, there's no way updating your array with one of the given syntax.
The only similar thing I can come on is looping over the array using array_walk ... http://www.php.net/manual/en/function.array-walk.php
Example:
array_walk($list, function($val, $key) use(&$list){
if ($val['name'] == 'Bobby') {
// If you'd use $val['group'] here you'd just editing a copy :)
$list[$key]['group'] = "someting";
}
});
EDIT: Example is using anonymous functions which is only possible since PHP 5.3. Documentation offers also ways working with older PHP-versions.
This code may help you:
$listSize = count($list);
for( $i = 0; $i < $listSize; ++$i ) {
if( $list[$i]['name'] == 'Bobby' ) {
$list[$i]['group'] = 'Hai';
}
}
array_push() doesn't really relate to updating a value, it only adds another value to an array.
You cannot have a solution that will fit both formats. The implicit array push $var[] is a syntactic construct, and you cannot invent new ones - certainly not in PHP, and not most (all?) other languages either.
Aside from that, what you are doing is not pushing an item on to the array. For one thing, pushing items implies an indexed array (yours is associative), and for another pushing implies adding a key to the array (the key you want to update already exists).
You can write a function to do it, something like this:
function array_update(&$array, $newData, $where = array(), $strict = FALSE) {
// Check input vars are arrays
if (!is_array($array) || !is_array($newData) || !is_array($where)) return FALSE;
$updated = 0;
foreach ($array as &$item) { // Loop main array
foreach ($where as $key => $val) { // Loop condition array and compare with current item
if (!isset($item[$key]) || (!$strict && $item[$key] != $val) || ($strict && $item[$key] !== $val)) {
continue 2; // if item is not a match, skip to the next one
}
}
// If we get this far, item should be updated
$item = array_merge($item, $newData);
$updated++;
}
return $updated;
}
// Usage
$newData = array(
'group' => '???'
);
$where = array(
'name' => 'Bobby'
);
array_update($list, $newData, $where);
// Input $array and $newData array are required, $where array can be omitted to
// update all items in $array. Supply TRUE to the forth argument to force strict
// typed comparisons when looking for item(s) to update. Multiple keys can be
// supplied in $where to match more than one condition.
// Returns the number of items in the input array that were modified, or FALSE on error.
Please i want to loop through my table and compare values with an array in a php included file. If there is a match, return the array key of the matched item and replace it with the value of the table. I need help in returning the array keys from the include file and comparing it with the table values.
$myarray = array(
"12aaa"=>"hammer",
"22bbb"=>"pinchbar",
"33ccr"=>"wood" );
in my loop in a seperate file
include 'myarray.inc.php';
while($row = $db->fetchAssoc()){
foreach($row as $key => $val)
if $val has a match in myarray.inc.php
{
$val = str_replace($val,my_array_key);
}
}
So in essence, if my db table has hammer and wood, $val will produce 12aaa and 3ccr in the loop. Any help? Thanks a lot
You are looking for array_search which will return the key associated with a given value, if it exists.
$result = array_search( $val, $myarray );
if ($result !== false) {
$val = $result;
}
your array should look like
$myarray = array(
"hammer"=>"11aaa",
"pinchbar"=>"22bbb",
"wood"=>"33ccr" );
and code
if (isset($myarray[$key])){
//do stuff
}
I think you need the function in_array($val, $myarray);
If you don't want or can't change $myarray structure like #genesis proposed, you can make use of array_flip
include 'myarray.inc.php';
$myarray = array_flip($myarray);
while($row = $db->fetchAssoc()) {
foreach($row as $key => $val) {
if (isset($myarray[$val])) {
// Maybe you should use other variable instead of $val to avoid confusion
$val = $myarray[$val];
// Rest of your code
}
}
}