I have an array thus (got this using var_dump):
array
0 =>
array
'post_id' => string '6' (length=1)
1 =>
array
'post_id' => string '9' (length=1)
I want to get the key when I have just the post_id. For example, I want '0' returned if I have '6' and '1' if I have '9'. I have tried:
$key = array_keys($subs, array_keys($subs[??], 6));
given that the $subs is the array. The issue is, I don't know how to iterate through the array 'within' the 'parent' array, hence, the '??'
I would use array_filter() and use to do this. Like this:
$array; // your array
$needle; // the value you are looking for
$filtered_array = array_filter($array, function ($element) use ($needle) {
return ($element['post_id'] === $needle);
});
$matching_keys = array_keys($filtered_array);
The array_filter() will filter down the input array to only those array element arrays that have a value for post_id that matches the value of $needle. You can use array_keys to get the key values for the remaining element(s) after the filter has been applied.
$post_id_to_find = '6';
$key = '';
foreach ($subs as $k1 => $v1)
{
foreach ($v1 as $k2 => $v2)
{
if ($post_id_to_find == $v2)
{
$key = $k1;
break;
}
}
}
Essentially what this code does is loop through the outer array and for each element loop through inner array, and if it finds the post id you want it'll set a variable that was initalized outside of the loops so after you break out of the loops you'll have the appropriate key.
EDIT
This is actually a pretty crappy answer, I realized you don't really need the inner loop since you know what key you want to check in the inner arrays... Anyway it seems like you used another answer, so this is pretty much moot.
Related
Suppose I have an array of indexes, A.
Suppose I have an array B, where every key is an array containing some indexes or number.
I would know which of the entries in B contain some index appearing in A.
For example (in php style):
A = [3,45,67,8]
B = [ 1 => [1,6,81],
2 => [5,67,3,4,5,66,6],
3 => [55,56,57,58],
4 => [45,80,81,82]
]
The entries of B which contain some value of A are 2 and 4.
So the function I would make should be:
function solution = filter(A,B) // solution = [2,4]
Now, with a brute loop, looping over entries of B, the complexity will be
O(nm), where n is #B and m is the size of longest row in B.
There are smarter solutions?
Edit #2:
By moving all values to be compared to key positions, php can more than double efficienct (by my demo's system time metric).
Furthermore, if you have duplicate values in your subsets, calling array_flip() will reduce the size by disallowing duplicate keys.
Code: (Demo)
$A = array_flip($A); // prepare for key comparisons
$result = [];
foreach ($B as $key => $haystack) {
if (array_intersect_key(array_flip($haystack), $A)) {
$result[] = $key;
}
}
var_export($result);
Edit:
Whenever you want to optimize array searching with php, it is often best to try to prepare your data in a way which allows php to leverage its strength with hash tables. https://codedmemes.com/lib/best-performance-array-intersection/
Consider this preparation...
Code: (Demo)
foreach ($B as $key => $haystack) {
foreach ($haystack as $hay) {
$C[$hay][] = $key;
}
}
var_export(array_keys(array_flip((array_merge(...array_intersect_key($C, array_flip($A)))))));
Output:
array (
0 => 1,
1 => 2,
2 => 4,
)
The nested foreach() loops generate a collection of subarrays which have unique values from B's subarrays as keys and $B's original keys as new subarray values.
array_intersect_key() checks the keys which php does much faster than checking values. (see first hyperlink article)
Then array_merge(...) flattens the subarrays into a single 1-dim array.
Finally array_flip() and array_keys() removes duplicates and re-indexes the results.
I don't know exactly how array_intersect() works its magic in terms of efficiency, but this is probably how I'd go about it:
Code: (Demo)
$A = [3,45,67,8];
$B = [ 1 => [1,6,8],
2 => [5,67,3,4,5,66,6],
3 => [55,56,57,58],
4 => [45,80,81,82]
];
$result = [];
foreach ($B as $key => $haystack) {
if (array_intersect($haystack, $A)) { // generate an array with co-existing values
$result[] = $key; // add key if array_intersect makes a non-empty array
}
}
var_export($result);
Output:
array (
0 => 1,
1 => 2,
2 => 4,
)
I suppose if there is a "downside" to using array_intersect() it would be that it will bother to make multiple matches, when only a single match per row is necessary. For this reason, array_search() or a breaking loop might have advantages.
Code: (Demo)
$result = [];
foreach ($B as $key => $haystack) {
foreach ($haystack as $hay) {
if (in_array($hay, $A)) {
$result[] = $key;
break;
}
}
}
var_export($result); // same result
I am trying to loop over certain array keys in drupal, but this is more of a generic php array question.
The array looks something like this...
$form['items'] = array(
#title => 'hello',
0 => array(
#subtitle => 'hello2';
),
1 => array(
#subtitle => 'hello2';
),
#prefix => '<div>hello</div>',
);
As you can see, the keys are a mix of numeric keys and #meta keys.
I am using this...
foreach($form['items'] as $x) {
unset($form['items'][$x]['column1']);
}
But i only want to target the numeric keys, I have tried is_numeric but it returned false.
Can someone tell me how to ignore the other keys? (Ignore #title and #prefix etc)
You want to check the keys, but you are using the value in your foreach. Do the following:
foreach($form['items'] as $key => $value) {
if (is_numeric($key))
unset($form['items'][$key]);
}
Hope I was helpful
Use is_int() rather than is_numberic()
foreach ($input_array as $key => $val) {
if (is_int($key)) {
// do stuff
}
}
Important to note that is_int only works on things that are type integer, meaning string representations are not allowed.
I need to do "foreach" action only for the highest parent nodes in my PHP array.
In this example I would like to get echo of the family lastnames...
$families = array(
'Brooks' => array(
'John',
'Ilsa',
),
'Hilberts' => array(
'Peter',
'Heidy',
));
foreach($families as $family){
// do some action that will return only "Brooks,Hilbers"
// not "Brooks,John,Ilsa,Hilbers,Peter,Heidy,Brooks,John,Ilsa,Hilberts,Peter,Heidy"
}
Is is handable, or should I define the array differently? Thank you very much for any positive answer.
You can simply return the key of the array (which is the family name):
foreach($families as $key => $family){
echo "FAMILY NAME = ".$key;
}
You can use the foreach just like ($array as $value) or like ($array as $key => $value). When the array is indexed (numerical key) the $key returns the position of the index (0, 1, 2...). When the array is associative (named keys), the $key returns the name of the index (in your example, Brooks, Hilberts, ...)
For more information please see PHP Arrays and Foreach Manual
I have two arrays, array1 and array2 that I am using to populate a table, so that array1[5] and array2[5] both fill the same row but I want to write a function that removes both array1[i] and array2[i] if array1[i] is a duplicate of array1[j] for some j less than i, where i is an arbitrary positive integer.
To accomplish this I was to work out the indices of duplicate values in array1 and then use this information to delete the entries from both array1 and array2 for these indices, before populating my table.
Any ideas gratefully received.
Thanks.
The array_unique function removes dupes, but preserves keys. Then you can just iterate through the other array and remove the keys that don't exist in the first one.
$array1 = array_unique($array1);
foreach ($array2 as $key => $val) {
if (!array_key_exists($key,$array1)) unset($array2[$key]);
}
$array1_keys = array_keys($array1); // all keys
$unique = array_keys(array_unique($array1)); // keys of unique values
$duplicate = array_diff($array1_keys, $unique_keys); // keys of the duplicate values
foreach($duplicate as $key){
unset($array2[$key]);
}
Sidenote: Be aware that array_diff uses string casting for comparison. If your array contains non scalar values you should have a look at array_udiff.
Edit: Mingos post in my eyes did not fully suit the question, looks like i was wrong :D
If your array keys are meaningful and not just a 0-based index and you want to keep the duplicate entry with the lowest key (as you indicate might be the case from your question) then you need to sort the array first. If you don't, you will get the first entry in the array for each duplicate value and not entry with the lowest key. Compare
$array = array( 5 => 'foo', 1 => 'bar', 2 => 'foo', 3 => 'bar' );
$array = array_unique( $array );
var_dump( $array );
with
$array = array( 5 => 'foo', 1 => 'bar', 2 => 'foo', 3 => 'bar' );
ksort( $array );
$array = array_unique( $array );
var_dump( $array );
In asociative arrays, you can get easily a counter of item to detect repeated and the first ocurrence with something as simple as (in this case using an associative array, where $array_key is the key to count) using array_count_values:
$index = null;
$array_by_columns = array_count_values(array_column($associative_array, $array_key);
foreach($array_by_columns) as $key => $ocurrences){
if($ocurrences > 1){
$index = $key;
}
}
If you have $index there are repeated element and also is the index of in the array.
A more compacted way in a line:
$index = null;
foreach(array_count_values(array_column($associative_array, $array_key)) as $key => $ocurrences)if($ocurrences > 1) $index = $key;
Data example:
[ARRAY] (start)
n0
KEY = 0
VALUE = {"user":"1","points":"10"}
n1
KEY = 1
VALUE = {"user":"4","points":"10"}
n2
KEY = 2
VALUE = {"user":"5","points":"30"}
n3
KEY = 3
VALUE = {"user":"1","points":"40"}
[ARRAY] (end)
More info:
array_count_values
array_column
I'm trying to find the key number in a array matching a string.
I tried array_search in this way
$key = array_search("foo", $array);
echo $array[$key];
but that prints $array[0]
Is there another way to do this?
Thanks :)
If the key is not found, array_search returns false. You have to check for that (line 3 in my example below)
$array = array(0 => 'blue', 1 => 'red', 2 => 'green', 3 => 'red');
$key = array_search("green", $array); //the $key will be "2"
if ($key !== false) {
echo $array[$key];
}
Otherwise, your code seems to do what you need. If there is a problem, please, post more code.
I'm not exactly matching the whole string, just one part, will array_search still work?
btw i made a loop through the array with for each that do a preg_match until it finds the string then breaks the loop and store the key in a array