PHP Intersection of array containing substrings of another one [duplicate] - php

This question already has answers here:
PHP check if array contains start of string
(4 answers)
Closed 3 months ago.
I have these 2 arrays:
array(
100 => 'this is some text',
161 => 'prefix1 : this is some text',
224 => 'some other text',
356 => 'prefix2 : some other text',
// ...
)
and
array(
0 => 'prefix1',
1 => 'prefix2',
// ...
)
The first array should not contain the prefixes, so I would like to identify the errors like this as a result:
array(
161 => 'prefix1 : this is some text',
356 => 'prefix2 : some other text',
// ...
)

You can use array_filter with str_contains like:
$a = [
100 => 'this is some text',
161 => 'prefix1 : this is some text',
224 => 'some other text',
356 => 'prefix2 : some other text',
];
$b = ['prefix1','prefix2'];
print_r(array_filter($a, function($a) use ($b){
foreach($b as $pref){
if(str_contains($a, $pref)){
return true;
}
}
}));
Output:
Array
(
[161] => prefix1 : this is some text
[356] => prefix2 : some other text
)
Example:
https://sandbox.onlinephpfunctions.com/c/c55a9
Reference:
array_filter
str_contains

Related

Keep array rows where a column value is found in a second flat array

** I have edited this to show how I got my code to work using array_search
I have an array, $arr1 with 5 columns as such:
key id name style age whim
0 14 bob big 33 no
1 72 jill big 22 yes
2 39 sue yes 111 yes
3 994 lucy small 23 no
4 15 sis med 24 no
5 16 maj med 87 yes
6 879 Ike larg 56 no
7 286 Jed big 23 yes
This array is in a cache, not a database.
I then have a second array with a list of id values -
$arr2 = array(0=>14, 1=>72, 2=>8790)
How do I filter $arr1 so it returns only the rows with the id values in $arr2?
I got my code to work as follows:
$arr1 = new CachedStuff(); // get cache
$resultingArray = []; // create an empty array to hold rows
$filter_function = function ($row) use ($arr2) {
return (array_search($row['id'], $arr2));
};
$resultingArrayIDs = $arr1->GetIds($filter_function, $resultingArray);
This gives me two outputs: $resultingArray & $resultingArrayIDs both of which represent the intersection of the $arr1 and $arr2.
This whole task can be accomplished with just one slick, native function call -- array_uintersect().
Because the two compared parameters in the custom callback may come either input array, try to access from the id column and if there isn't one declered, then fallback to the parameter's value.
Under the hood, this function performs sorting while evaluating as a means to improve execution time / processing speed. I expect this approach to outperform iterated calls of in_array() purely from a point of minimized function calls.
Code: (Demo)
var_export(
array_uintersect(
$arr1,
$arr2,
fn($a, $b) =>
($a['id'] ?? $a)
<=>
($b['id'] ?? $b)
)
);
Something like this should do it, provided I've understood your question and data structure correctly:
$dataArray = [
[ 'key' => 0, 'id' => 14 , 'name' => 'bob' , 'style' => 'big' , 'age' => 33 , 'whim' => 'no' ],
[ 'key' => 1, 'id' => 72 , 'name' => 'jill' , 'style' => 'big' , 'age' => 22 , 'whim' => 'yes' ],
[ 'key' => 2, 'id' => 39 , 'name' => 'sue' , 'style' => 'yes' , 'age' => 111 , 'whim' => 'yes' ],
[ 'key' => 3, 'id' => 994 , 'name' => 'lucy' , 'style' => 'small' , 'age' => 23 , 'whim' => 'no' ],
[ 'key' => 4, 'id' => 15 , 'name' => 'sis' , 'style' => 'med' , 'age' => 24 , 'whim' => 'no' ],
[ 'key' => 5, 'id' => 16 , 'name' => 'maj' , 'style' => 'med' , 'age' => 87 , 'whim' => 'yes' ],
[ 'key' => 6, 'id' => 879 , 'name' => 'Ike' , 'style' => 'larg' , 'age' => 56 , 'whim' => 'no' ],
[ 'key' => 7, 'id' => 286 , 'name' => 'Jed' , 'style' => 'big' , 'age' => 23 , 'whim' => 'yes' ]
];
$filterArray = [14, 72, 879];
$resultArray = array_filter( $dataArray, function( $row ) use ( $filterArray ) {
return in_array( $row[ 'id' ], $filterArray );
} );
View this example on eval.in
However, your question appears to suggest this data might be coming from a database; is that correct? If so, perhaps it's more efficient to pre-filter the results at the database-level. Either by adding a field in the SELECT query, that represents a boolean value whether a row matched your filter ids, or by simply not returning the other rows at all.
One way is with foreach loop with array_search()
$result = [];
foreach ($arr1 as $value) { // Loop thru $arr1
if (array_search($value['id'], $arr2) !== false) { // Check if id is in $arr2
$result[] = $value; // Push to result if true
}
}
// print result
print_r($result);
As #DecentDabbler mentioned - if the data is coming out of a database, using an IN on your WHERE will allow you to retrieve only the relevant data.
Another way to filter is to use array functions
array_column extracts the value of the id column into an array
array_intersect returns the elements which are in both $arr1['id'] and $arr2
array_flip flips the resulting array such that the indices into $arr1 indicate the elements in both $arr1 and $arr2
$arr1 = [ [ 'id' => 14, 'name' => 'bob'],
['id' => 72, 'name' => 'jill'],
['id' => 39, 'name' => 'sue'],
['id' => 994, 'name' => 'lucy'],
['id' => 879, 'name'=> 'large']];
$arr2 = [ 14,72,879 ];
$intersection = array_flip(array_intersect(array_column($arr1,'id'),$arr2));
foreach ($intersection as $i) {
var_dump($arr1[$i]);;
}

MAX in PHP returning wrong value

I have an array with key and value pair. I'm building this array dynamically and below is the code.
$x[] = array('type_name' => $value->name,
'percentage'=> intval($percentage));
My intention is to get the maximum value and for that I do
max($x);
However it is returning the wrong value actually the lowest value. Following is my array. Any help would be awesome.
$x = array(
array(
'type_name' => 'type 1'
'percentage' => 10,
),
array(
'type_name' => 'type 2'
'percentage' => 15,
),
array(
'type_name' => 'type 3'
'percentage' => 45,
),
);
Thanks is advance.
From php max() documentation :
// Multiple arrays of the same length are compared from left to right
It means that if you want to compare "percentage" values first instead of "type_name" values, you'll have to change their order in the array.
So, you could build your array like this ("percentage" comes first) and it should work :
$x[] = array(
'percentage'=> intval($percentage),
'type_name' => $value->name
);
For example :
$x = array(
array(
'percentage' => 10,
'type_name' => 'type 1'
),
array(
'percentage' => 15,
'type_name' => 'type 2'
),
array(
'percentage' => 45,
'type_name' => 'type 3'
),
array(
'percentage' => 25,
'type_name' => 'type 4'
)
);
print_r(max($x));
Output :
Array
(
[percentage] => 45
[type_name] => type 3
)
Hope it helps.
You need to read how the max compares against different types of data. In your case, you are trying to compare against one of the array item i.e. percentage inside one of the item so the function max does not know to do this.
There is an example by Revo in the manual which shows you how to do this.
You are creating an array of arrays. max doesn’t know that your arrays should be compared by the 'percentage' key, so it can’t be used here.
Instead, find the maximum value yourself. For example, like this:
$maxPercentage = false;
foreach ($x as $item) {
if ($maxPercentage === false || $item['percentage'] > $maxPercentage) {
$maxPercentage = $item['percentage'];
}
}
Now, $maxPercentage will store maximum percentage. Of, if you want an item with maximum percentage, get it like this:
$maxPercentage = false;
$maxItem = false;
foreach ($x as $item) {
if ($maxPercentage === false || $item['percentage'] > $maxPercentage) {
$maxPercentage = $item['percentage'];
$maxItem = $item;
}
}

Get the intersect of tables

I have a question. So I have this array :
$a_list_id = array(
0 => 1234
1 => 739
3 => 538
);
And this array :
$a_users = array(
0 => array(
id => 15627,
name => test
),
1 => array(
id => 1234,
name => test1
),
2 => array(
id => 739,
name => test2
)
)
The result should be :
$a_response = array(
0 => array(
id => 1234,
name => test1
)
)
Because the id 1234 is in both arrays.
I try with array_intersect but not work. Can you help me please ?
Just use loops :
$a_response = array();
foreach ($a_users as $array) {
if (in_array($array['id'], $a_list_id)) {
$a_response []= $a_users;
}
}
array_intersect will only produce useful results if the values of both arrays can be cast to the same type. You've got an array of integers and another array of arrays, they can never* match so intersect will always be empty
If you want an intersection between the arrays then you have two options:
Index the arrays so their keys are the values you want to intersect and use array_intersect_key
Implement your own array comparison logic with array_uintersect and a callback function that knows the structure of the arrays being compared
example of the former:
$a_list_id = array(
1234 => 1234
739 => 739
538 => 538
);
$a_users = array(
15627 => array(
id => 15627,
name => test
),
1234 => array(
id => 1234,
name => test1
),
739 => array(
id => 739,
name => test2
)
)
var_dump (array_intersect_key ($a_users, $a_list_id));
Example of the latter:
var_dump (array_uintersect ($a_users, $a_list_id, function ($user, $id) {
return $user ["id"] - $id; // Result should be 0 if they match, as per documentation
}))
*They can be considered the same in the case where one value is integer 0 and the other is an empty array, but that's not very useful
Try the below code using array_search() function:
$a_list_id = array(1234, 538,739);
$a_users = array(
array(
'id'=> 15627,
'name' => 'test'
),
array(
'id' => 1234,
'name' => 'test1'
),
array(
'id' => 739,
'name' => 'test2'
)
);
foreach($a_users as $a_user){
if (in_array($a_user['id'], $a_list_id)) {
$a_response[array_search($a_user['id'], $a_list_id)] = $a_user;
}
}
print_r($a_response);
Have you tried using array_intersect_uassoc? http://php.net/manual/en/function.array-intersect-uassoc.php
function compare_ids($a, $b)
{
return $a - $b['id'];
}
print_r(array_intersect_uassoc($a_list_id, $a_users, "compare_ids"));

Transpose an array of arrays [duplicate]

This question already has answers here:
Transposing multidimensional arrays in PHP
(12 answers)
Closed 6 months ago.
Hah, I had no idea how else to phrase that. I'm trying to reformat a set of three arrays generated by form field inputs, into something that better matches my models, so I can save the values to the db.
Not sure if the solution should be some array manipulation or that I should change the "name" attribute in my form fields.
currently I have an array of my input data:
array(
'image_id' =>
array
0 => '454' (length=3),
1 => '455' (length=3),
2 => '456' (length=3)
'title' =>
array
0 => 'title1' (length=6),
1 => 'title2' (length=0),
2 => '' (length=6)
'caption' =>
array
0 => 'caption1' (length=8),
1 => '' (length=8),
2 => 'caption3' (length=8)
);
and would like to change it to something like, so I can iterate over and save each array of values to the corresponding resource in my db.
array(
0 =>
array
'image_id' => '454',
'title' => 'title1',
'caption' => 'caption1'
1 =>
array
'image_id' => '455',
'title' => 'title2',
'caption' => ''
2 =>
array
'image_id' => '456',
'title' => '',
'caption' => 'caption3'
);
This would iterate through the array with 2 foreach loops. They would use each other's key to construct the new array, so it would work in any case:
$data = array(
'image_id' => array(454, 455, 456),
'title' => array('title1', 'title2', ''),
'caption' => array('caption1', '', 'caption3')
);
$result = array();
foreach($data as $key => $value) {
foreach ($value as $k => $v) {
$result[$k][$key] = $v;
}
}
This'll do it:
$array = call_user_func_array('array_map', array_merge(
[function () use ($array) { return array_combine(array_keys($array), func_get_args()); }],
$array
));
Assuming though that this data is originally coming from an HTML form, you can fix the data right there already:
<input name="data[0][image_id]">
<input name="data[0][title]">
<input name="data[0][caption]">
<input name="data[1][image_id]">
<input name="data[1][title]">
<input name="data[1][caption]">
Then it will get to your server in the correct format already.

Applying a custom order to a multi-dimensional array

I have this array
$arr = array(
'one' => array(
'slidertitle' => 'lorem ipsum',
'sliderlocation' => 'http://localhost/images/1.jpg',
'sliderdescription' => 'this is a good lorem ipsum image',
'sliderposition' => 1
),
'two' => array(
'slidertitle' => 'second slider',
'sliderlocation' => 'http://localhost/images/2.jpg',
'sliderdescription' => 'this space was reserved for a link source code here',
'sliderposition' => 2
),
'six' => array(
'slidertitle' => 'sixth slider',
'sliderlocation' => 'http://localhost/images/6.jpg',
'sliderdescription' => 'this is the sixth slider,like,really!',
'sliderposition' => 6
)
);
which i need to look like this
$arr = array(
'two' => array(
'slidertitle' => 'second slider',
'sliderlocation' => 'http://localhost/images/2.jpg',
'sliderdescription' => 'this space was reserved for a link source code here',
'sliderposition' => 2
),
'six' => array(
'slidertitle' => 'sixth slider',
'sliderlocation' => 'http://localhost/images/6.jpg',
'sliderdescription' => 'this is the sixth slider,like,really!',
'sliderposition' => 6
),
'one' => array(
'slidertitle' => 'lorem ipsum',
'sliderlocation' => 'http://localhost/images/1.jpg',
'sliderdescription' => 'this is a good lorem ipsum image',
'sliderposition' => 1
)
);
I am attempting to do that by defining the expected array structure and introducing a dummy array.I then chunk the array and merge each chunk to the array format and i plan to finally unset the dummy and i am left with the array i want and in the order i want.
$arrayFormat = array(
'dummy' => array(
'slidertitle' => 'xxxx',
'sliderlocation' => 'xxxxxxx',
'sliderdescription' => 'xxxxxx',
'sliderposition' => 0
)
);
$arrayLength = count($arr);
$afterChunk = array_chunk($arr,$arrayLength);
$one = $afterChunk[0][0];
$two = $afterChunk[0][1];
$mergedArray = array_merge($arrayFormat,$one);
$secondMergedArray = array_merge($mergedArray,$two);
echo '<pre>';
print_r($secondMergedArray);
echo '</pre>';
The problem is array_chunk() does not include the key of the array so i am getting
Array (
[dummy] => Array
(
[slidertitle] => xxxx
[sliderlocation] => xxxxxxx
[sliderdescription] => xxxxxx
[sliderposition] => 0
)
[slidertitle] => second slider
[sliderlocation] => http://localhost/images/2.jpg
[sliderdescription] => this space was reserved for a link source code here
[sliderposition] => 2 )
when i print_r($secondMergedArray);.is there something that can be done to array_chunk() to include the array key or is there any other array function that can help me get individual array inclusive of the key?.
It's really hard to tell what you're wanting in terms of how to sort the elements. You've not been very clear in the question. There has to be something in the array that you know what order it needs to be.
In the absence of any clues as to what that is, I'm going to assume you want to specify the order of the array keys manually.
So, the current array is array('one'=>... , 'two'=>... , 'six'=>... ) and you want to sort those keys in an order you want to specify manually.
The solution is to use the uksort() function, along with a separate array specifying your sort order:
$arr = ... //input array as specified in the question
$sortOrder = array('two','one','six');
uksort($arr, function ($a, $b) use ($sortOrder) {
$sortMe = array_flip($sortOrder);
if ($sortMe[$a] == $sortMe[$b]) { return 0; }
return ($sortMe[$a] < $sortMe[$b]) ? -1 : 1;
});
print_r($arr);
Outputs your array in 'two','one','six' order. Change the $sortOrder array as required.
Hope that helps.
Note: the syntax I've provided above only works in PHP 5.3 and above. (if you're using an older version, you need to upgrade)
use uksort() for custom order for multidimensional array
http://php.net/manual/en/function.uksort.php

Categories