How can i match 2 arrays and attach prefix to matching values? - php

I have 2 arrays:
a1 = 1,2,3,4,5,6,7,8
a2 = 1,3,5,7
I want to be able to compare both arrays where they match, combine them without duplicates and then attach a prefix or letter to the matching values.
expected result:
a3 - match1,2,match3,4,match5,6,match7,8
I have looked at array_intersect(), but I'm not sure how I would use it in my example.

This could be one for https://adventofcode.com !
This is probably not the most efficient solution performance- or memory-wise, but it should do the trick.
$a1 = [1,2,3,4,5];
$a2 = [1,3,5];
$result = [];
foreach($a1 as $item) {
if (in_array($item, $a2)) {
$result[] = 'match' . $item;
} else {
$result[] = $item;
}
}
See it in action here: https://3v4l.org/PlTIZ

Alternatively, You can use array_map() to achieve this with better performance and maintainable code.
Live demo.
$arr_one = [1,2,3,4,5];
$arr_two = [1,3,5];
$new_arr = array_map(function($arg) use ($arr_two) {
return in_array($arg, $arr_two) ? "prefix_{$arg}" : $arg;
}, $arr_one);
Output:
array(5) {
[0]=>
string(8) "prefix_1"
[1]=>
int(2)
[2]=>
string(8) "prefix_3"
[3]=>
int(4)
[4]=>
string(8) "prefix_5"
}
References
array_* → pre-built methods.
ternary operator → ? :

Related

PHP usort in custom order

I am trying to sort array, lets say :
['qwe',12,'*', 324, '$we'], but I want it to sort : first numbers, then special characters and letters at last.
I know that I have to use usort(), but am not sure how to write callback function to achieve what I need.
Any ideas?
If you are trying to sort the elements in the array, and not the characters within the elements themselves, you could use the following, ugly but functional, solution:
$array = ['qwe',12,'*', 324, '$we'];
$nums = $spec = $letters = array();
foreach ($array as $i) {
if (is_numeric($i)) {
array_push($nums, $i);
}
else if (ctype_alpha($i)) {
array_push($letters, $i);
}
else if (preg_match('/[\'^£$%&*()}{##~?><>,|=_+¬-]/', $i)) {
array_push($spec, $i);
}
}
sort($nums);
sort($letters);
sort($spec);
$sorted = array_merge($nums,$spec,$letters);
var_dump($sorted);
This will iterate through your initial array and add each item to a different array, basing on its type (regex used to detect symbols). Then the single arrays are alphabetically sorted, and merged in the order of your liking.
The above code will output:
array(5) {
[0]=>
int(12)
[1]=>
int(324)
[2]=>
string(3) "$we"
[3]=>
string(1) "*"
[4]=>
string(3) "qwe"
}

Remove the first 3 levels from multidimensional array

I've trying to remove the first 3 levels from my multidimensional array, is there a 'cleaner' way to perform the below code?
$array = array_shift(array_shift(array_shift($this->fullArray())));
This is the array
array(1) {
["GetAllJobByLanguageResult"]=> array(1) {
["Results"]=> array(1) {
["AvJobSearch"]=> array(2) {
[0]=> array(21) {
["Id"]=> int(103689)
["Title"]=> string(13) "Test Vacature"
["PublishDate"]=> string(23) "2018-06-08T14:11:05.237"
You can loop the number of levels you want to remove.
I use array_keys to find the keys and overwrite $arr with $arr one level deeper.
This is then repeated the number of times specified in the for loop.
$arr = [["second" => ["something" => ["else" => [1,2,3]]]]];
For($i=0;$i<3;$i++){
$keys = array_keys($arr);
$arr = $arr[$keys[0]];
}
Var_dump($arr);
https://3v4l.org/WiOrI
If you know the exact path then you can skip the loop and just write:
$arr = $arr[0]["second"]["something"];
But the loop is useful if you are not sure what the keys are.
you are using a static way to remove elements of array and array_shift is not for remove elements
Try by this
<?php
$a = array("a"=>"red","b"=>"green","c"=>"blue");
$i=1;
foreach($a as $key=>$value){
if($i < 3){
unset($a[$key]);
}
$i++;
}
print_r($a);

Updating a value in a multidimensionnal array regarding another value and using array_walk (PHP)

I would like to update the values of a multidimensionnal php array : $a
array(1) {
["test"]=> array(4) {
[0]=> int(5)
[1]=> int(7)
[2]=> int(10)
[3]=> int(14)
}
}
For $a["test"][$i], I would like to obtain this new value $a["test"][$i] - $a["test"][$i-1].
In this case the resulting array would be :
array(1) {
["test"]=> array(4) {
[0]=> int(5)
[1]=> int(2)
[2]=> int(3)
[3]=> int(4)
}
}
Of course, I could do it with a foreach loop and a new array
$new = array();
foreach($a as $k=>$v){
for($i=0;$i<=3;$i++){
$new[$k][$i] = $v[$i] - $v[$i-1];
}
}
$a = $new;
var_dump($a);
but is this the best way? Just out of curiosity, I was wondering if using array_walk to make it could be nicer and, generally, how/if array_walk could access the previous/next value in the array.
Thank you a lot !
PHP code demo
<?php
$array = array(
"test" => array(5, 7, 10, 14)
);
$new=array();
array_walk($array["test"], function($value,$key) use (&$new,&$array){
if($key>0)
{
$new["test"][]=$array["test"][$key]-$array["test"][$key-1];
}
else
{
$new["test"][]=$value;
}
});
print_r($new);
Or:
PHP code demo
<?php
$array = array(
"test" => array(5, 7, 10, 14)
);
$newArray=array();
foreach($array["test"] as $key => $value)
{
if($key>0)
{
$newArray["test"][]=$array["test"][$key]-$array["test"][$key-1];
}
else
{
$newArray["test"][]=$value;
}
}
print_r($newArray);
Since you're overwriting the original array with the new values in the end anyway, you might as well just change the values of the original array as you go.
A custom function can do the successive subtraction for each subset.
function successive_subtraction(&$array) {
$subtrahend = 0; // store the previous value for subtraction
foreach ($array as &$value) {
$temp = $value; // store the current value in a temporary variable
$value -= $subtrahend; // subtract the previous value
$subtrahend = $temp; // original current value become new previous value
}
}
Then apply that function to each element of the outer array with array_walk.
array_walk($a, 'successive_subtraction');
This code is actually more complex that the way you're already doing it. The main advantage to modifying the existing array rather than creating a modified copy and then overwriting it would be less peak memory usage, but if the arrays you're dealing with aren't very large, then that shouldn't really be a problem, and I would say just keep it simple.

Get array with regex from string

I got an php array like this:
array(3) {
[0]=> string(12) "server[edit]"
[1]=> string(14) "server[create]"
[2]=> string(12) "user[delete]"
}
I want to convert this to different arrays - for example an array named server with "edit" and "create" in it - and another array "user" with "delete".
Whats the right pattern for that ?
Thanks for any help!
Rather than trying a regex against the whole array, try matching against each individual value. Take a look at this as an example
$array = array(
'server[edit]',
'server[create]',
'user[delete]',
'dsadsa'
);
$newArray = array();
foreach($array as $value)
{
preg_match("~^(\w+)\[(\w+)\]$~", $value, $matches);
if(count($matches))
{
$key = $matches[1];
if(!isset($newArray[$key]))
$newArray[$key] = array();
$newArray[$key][] = $matches[2];
}
}
var_dump($newArray);

Remove elements from array of objects that contain the same name

How do I remove elements from an array of objects with the same name? In the case below, I want to remove elements 0 and 2 because the name is the same. I figured I could loop over every case but that seems wasteful.
array(1) {
[0]=> object(stdClass)#268 (3) {
["term_id"]=> string(3) "486"
["name"]=> string(4) "2012"
["count"]=> string(2) "40"
}
[1]=> object(stdClass)#271 (3) {
["term_id"]=> string(3) "488"
["name"]=> string(8) "One more"
["count"]=> string(2) "20"
}
[2]=> object(stdClass)#275 (3) {
["term_id"]=> string(3) "512"
["name"]=> string(8) "2012"
["count"]=> string(2) "50"
}
You can loop over the array, calculating how many times each name appears. Then you filter away those elements appearing more than once using array_filter. This will have an average runtime complexity of O(n) (assuming O(1) for arrays), compared to the naive O(n^2) case.
Code:
$counter = array();
foreach($array as $val) {
$n = $val->name;
$counter[$n] = (!isset($counter[$n])) ? 1 : 2;
}
$result = array_filter(
$array,
function ($item) use ($counter) { return $counter[$item->name] == 1; }
);
For PHP versions before 5.3 you cannot use closures, so in that case, modify your code to this:
$counter = array();
foreach($array as $val) {
$n = $val->name;
$counter[$n] = (!isset($counter[$n])) ? 1 : 2;
}
function my_filter($item) {
global $counter;
return $counter[$item->name] == 1;
}
$result = array_filter(
$array,
'my_filter'
);
Note that this is only useful in reality for large arrays since there's some overhead involved. It may also be hard to read if you don't understand what's being done. For small arrays (a few hundred elements or so) I recommend you to use the naive quadratic-time loop approach.
If it are objects of classes you can modify, you could let the __toString() method return the name property and use array_unique():
Two elements are considered equal if and only if (string) $elem1 === (string) $elem2. In words: when the string representation is the same. The first element will be used.
$result = array_filter(
$array,
function ($item) use ($name) { return $item->name != $name; }
);
Note, that this is exactly this "loop over every case" you mentioned. There is no other solution, if you want to check every item.

Categories