How to merge two arrays by its values in PHP? - php

What I need is really simple:
I have two arrays like that:
<?php
$a1 = [1,2,3];
$a2 = [2,3,4];
I need to combine them so that the result is:
$result = [1,2,3,4];
I've tried array_merge but the result was [1,2,3,2,3,4]

You can find an answer to this here: Set Theory Union of arrays in PHP
By expanding on your current method. You can call array_unique and sort on the resulting array.
$a = [1,2,3];
$b = [2,3,4];
$result = array_merge($a, $b);
$result = array_unique($result);
sort($result);
This will result in:
array(4) {
[0] = int(1) 1
[1] = int(1) 2
[2] = int(1) 3
[3] = int(1) 4
}

function merges(/*...*/){
$args=func_get_args();
$ret=array();
foreach($args as $arg){
foreach($arg as $key=>$v)
{
$ret[$key]=$v;
}
}
return $ret;
}
untested, but i guess this would work.. will delete all duplicate keys and return the last key/value pair it found of duplicates

This might be what you are looking for
$result = $a1 + $a2 //union operation
reference
Array Operations
Example
$a = array("a" => "apple", "b" => "banana");
$b = array("a" => "pear", "b" => "strawberry", "c" => "cherry");
$c = $a + $b; // Union of $a and $b
echo "Union of \$a and \$b: \n";
var_dump($c);
Ouput
Union of $a and $b:
array(3) {
["a"]=>
string(5) "apple"
["b"]=>
string(6) "banana"
["c"]=>
string(6) "cherry"
}

Related

PHP combine key value array and regular array

I have 2 arrays:
array1 :
[0]=>
string(10) "AAAAAAAAAAA"
[1]=>
string(10) "BBBBBBBBBBB"
...
and array2:
[0]=>
float(0)
[550]=>
float(55)
...
I need a result like this:
"AAAAAAAAAAA" : 0 : 0
"BBBBBBBBBBB" : 550: 55
...
i.e. how to combine the arrays. How do i get that?
suppose you two arrays have the same length,
$keys = array_keys($array1);
$values = [];
foreach($array2 as $k=>$v)
{
$values[] = $k.':'.$v;
}
$result = array_combine($keys, $values);
The result you want is not clear... if each rows are just a string, this should work :
$a = [
0 => "AAAAAAAAAAA",
1 => "BBBBBBBBBBB"
];
$b = [
0 => (float) 0,
550 => (float) 55
];
$result = array_map(
function($v1, $v2, $v3) {
return "$v1 : $v2 : $v3";
},
$a, array_keys($b), $b
);
var_dump($result);

PHP array elements replace

I want to make some encryption and write numbers
I used:
$a = [100,101,102,103,104,105]
function decrition (array $a){
return preg_replace('/101/','a',$a);
}
And it's returns me all letters "a" for each 101 in array.
How can I change next? 101 to "b", 102 to "c" etc.
return preg_replace('[101|102|103|104|105]','a',$a);
this method replace all this numbers to letter "a"
return preg_replace('[101|102|103|104|105','a|b|c|d|e',$a);
unfortunately it's not working
Why do you try to treat it as a string?
<?php
$a = [ 101, 102, 103 ];
$replace_array = array(101 => "a", 102 => "b");
$b = array_map(function($val) use ($replace_array) {
return (isset($replace_array[$val]) ? $replace_array[$val] : $val);
}, $a);
var_dump($a, $b);
Gives the following output:
array(3) {
[0]=>
int(101)
[1]=>
int(102)
[2]=>
int(103)
}
array(3) {
[0]=>
string(1) "a"
[1]=>
string(1) "b"
[2]=>
int(103)
}
Maybe you are looking for something like this?
$test = str_replace($a, array('a','b','c','d','e','f'), $a);
print_r($test);
This solution works
return str_replace(['101', '102', '103', '104', '105'], ['a', 'b', 'c', 'd', 'e'], $a);

Split array to create an associative array

I have an array that looks like this:
a 12 34
b 12345
c 123456
So the array looks like
$array[0] = "a 12 34"
$array[1] = "b 12345"
$array[2] = "c 123456"
I am trying to create an associative array such that
[a] => 12 34
[b] => 12345
[c] => 123456
Can I possibly split the array into two, one for containing "a, b, c" and another for their contents and use the array_combine()? Or are there any other ways?
You can do that within a loop like the snippet below demonstrates. Quick-Test here:
$array = array("a 12 34", "b 12345", "c 123456");
$array2 = array();
foreach($array as $data){
preg_match("#([a-z])(\s)(.*)#i", $data, $matches);
list(, $key, $space, $value) = $matches;
$array2[$key] = $value;
}
var_dump($array2);
// YIELDS::
array(3) {
["a"]=> string(5) "12 34"
["b"]=> string(5) "12345"
["c"]=> string(6) "123456"
}
Or using a Blend of array_walk() and array_combine() which can be Quick-Tested Here.
<?php
$array = array("a 12 34", "b 12345", "c 123456");
$keys = array();
array_walk($array, function(&$data, $key) use (&$keys){
$keys[] = trim(preg_replace('#(\s.*)#i', '', $data));;
$data = trim(preg_replace('#(^[a-z])#i', '', $data));
});
$array = array_combine($keys, $array);
var_dump($array);;
// YIELDS::
array(3) {
["a"]=> string(5) "12 34"
["b"]=> string(5) "12345"
["c"]=> string(6) "123456"
}
You can do it without any difficulty :) A simple loop is possible to do it.
Create new array
Lopp on each row
Split each data (explode(' ', $row, 2), strstr, substr, ...) ?
Put data on your new array $array[$key] = $value;
You could use a combination of array_map, array_column and array_combine:
$array = array_map(function ($v) { return explode(' ', $v, 2); }, $array);
$array = array_combine(array_column($array, 0), array_column($array, 1));

sort Array in specific filename order

How do I sort the following data in the order I want it?
The array:
array(4)
{
[21]=> string(7) "2-2.pdf"
[22]=> string(7) "2-3.pdf"
[23]=> string(7) "2-4.pdf"
[24]=> string(5) "2.pdf"
}
I want this sort:
2.pdf
2-2.pdf
2-3.pdf
2-4.pdf
Yes you could use usort in this case:
$array = [21=> "2-2.pdf", 22=> "2-3.pdf", 23=> "2-4.pdf",24=> "2.pdf", ];
usort($array, function($a, $b){
$a = str_replace('-', '', $a);
$b = str_replace('-', '', $b);
return $a - $b;
});
You can do like this:
<?php
$check_array = array('2-2.pdf','2.pdf','2-3.pdf','2-4.pdf');
function cmp($a, $b)
{
$a = preg_replace('/-/','',$a);
$b = preg_replace('/-/','',$b);
return strcmp($a, $b);
}
usort($check_array, "cmp");
echo "<pre/>"; print_r($check_array);
?>
And the result is:
<?php Array ( [0] => 2.pdf [1] => 2-2.pdf [2] => 2-3.pdf [3] => 2-4.pdf ) ?>

PHP append one array to another (not array_push or +)

How to append one array to another without comparing their keys?
$a = array( 'a', 'b' );
$b = array( 'c', 'd' );
At the end it should be: Array( [0]=>a [1]=>b [2]=>c [3]=>d )
If I use something like [] or array_push, it will cause one of these results:
Array( [0]=>a [1]=>b [2]=>Array( [0]=>c [1]=>d ) )
//or
Array( [0]=>c [1]=>d )
It just should be something, doing this, but in a more elegant way:
foreach ( $b AS $var )
$a[] = $var;
array_merge is the elegant way:
$a = array('a', 'b');
$b = array('c', 'd');
$merge = array_merge($a, $b);
// $merge is now equals to array('a','b','c','d');
Doing something like:
$merge = $a + $b;
// $merge now equals array('a','b')
Will not work, because the + operator does not actually merge them. If they $a has the same keys as $b, it won't do anything.
Another way to do this in PHP 5.6+ would be to use the ... token
$a = array('a', 'b');
$b = array('c', 'd');
array_push($a, ...$b);
// $a is now equals to array('a','b','c','d');
This will also work with any Traversable
$a = array('a', 'b');
$b = new ArrayIterator(array('c', 'd'));
array_push($a, ...$b);
// $a is now equals to array('a','b','c','d');
A warning though:
in PHP versions before 7.3 this will cause a fatal error if $b is an empty array or not traversable e.g. not an array
in PHP 7.3 a warning will be raised if $b is not traversable
Why not use
$appended = array_merge($a,$b);
Why don't you want to use this, the correct, built-in method.
It's a pretty old post, but I want to add something about appending one array to another:
If
one or both arrays have associative keys
the keys of both arrays don't matter
you can use array functions like this:
array_merge(array_values($array), array_values($appendArray));
array_merge doesn't merge numeric keys so it appends all values of $appendArray. While using native php functions instead of a foreach-loop, it should be faster on arrays with a lot of elements.
Addition 2019-12-13:
Since PHP 7.4, there is the possibility to append or prepend arrays the Array Spread Operator way:
$a = [3, 4];
$b = [1, 2, ...$a];
As before, keys can be an issue with this new feature:
$a = ['a' => 3, 'b' => 4];
$b = ['c' => 1, 'a' => 2, ...$a];
"Fatal error: Uncaught Error: Cannot unpack array with string keys"
$a = [3 => 3, 4 => 4];
$b = [1 => 1, 4 => 2, ...$a];
array(4) {
[1]=>
int(1)
[4]=>
int(2)
[5]=>
int(3)
[6]=>
int(4)
}
$a = [1 => 1, 2 => 2];
$b = [...$a, 3 => 3, 1 => 4];
array(3) {
[0]=>
int(1)
[1]=>
int(4)
[3]=>
int(3)
}
<?php
// Example 1 [Merging associative arrays. When two or more arrays have same key
// then the last array key value overrides the others one]
$array1 = array("a" => "JAVA", "b" => "ASP");
$array2 = array("c" => "C", "b" => "PHP");
echo " <br> Example 1 Output: <br>";
print_r(array_merge($array1,$array2));
// Example 2 [When you want to merge arrays having integer keys and
//want to reset integer keys to start from 0 then use array_merge() function]
$array3 =array(5 => "CSS",6 => "CSS3");
$array4 =array(8 => "JAVASCRIPT",9 => "HTML");
echo " <br> Example 2 Output: <br>";
print_r(array_merge($array3,$array4));
// Example 3 [When you want to merge arrays having integer keys and
// want to retain integer keys as it is then use PLUS (+) operator to merge arrays]
$array5 =array(5 => "CSS",6 => "CSS3");
$array6 =array(8 => "JAVASCRIPT",9 => "HTML");
echo " <br> Example 3 Output: <br>";
print_r($array5+$array6);
// Example 4 [When single array pass to array_merge having integer keys
// then the array return by array_merge have integer keys starting from 0]
$array7 =array(3 => "CSS",4 => "CSS3");
echo " <br> Example 4 Output: <br>";
print_r(array_merge($array7));
?>
Output:
Example 1 Output:
Array
(
[a] => JAVA
[b] => PHP
[c] => C
)
Example 2 Output:
Array
(
[0] => CSS
[1] => CSS3
[2] => JAVASCRIPT
[3] => HTML
)
Example 3 Output:
Array
(
[5] => CSS
[6] => CSS3
[8] => JAVASCRIPT
[9] => HTML
)
Example 4 Output:
Array
(
[0] => CSS
[1] => CSS3
)
Reference Source Code
Following on from answer's by bstoney and Snark I did some tests on the various methods:
// Test 1 (array_merge)
$array1 = $array2 = array_fill(0, 50000, 'aa');
$start = microtime(true);
$array1 = array_merge($array1, $array2);
printf("Test 1: %.06f\n", microtime(true) - $start);
// Test2 (foreach)
$array1 = $array2 = array_fill(0, 50000, 'aa');
$start = microtime(true);
foreach ($array2 as $v) {
$array1[] = $v;
}
printf("Test 2: %.06f\n", microtime(true) - $start);
// Test 3 (... token)
// PHP 5.6+ and produces error if $array2 is empty
$array1 = $array2 = array_fill(0, 50000, 'aa');
$start = microtime(true);
array_push($array1, ...$array2);
printf("Test 3: %.06f\n", microtime(true) - $start);
Which produces:
Test 1: 0.002717
Test 2: 0.006922
Test 3: 0.004744
ORIGINAL: I believe as of PHP 7, method 3 is a significantly better alternative due to the way foreach loops now act, which is to make a copy of the array being iterated over.
Whilst method 3 isn't strictly an answer to the criteria of 'not array_push' in the question, it is one line and the most high performance in all respects, I think the question was asked before the ... syntax was an option.
UPDATE 25/03/2020:
I've updated the test which was flawed as the variables weren't reset. Interestingly (or confusingly) the results now show as test 1 being the fastest, where it was the slowest, having gone from 0.008392 to 0.002717! This can only be down to PHP updates, as this wouldn't have been affected by the testing flaw.
So, the saga continues, I will start using array_merge from now on!
For big array, is better to concatenate without array_merge, for avoid a memory copy.
$array1 = array_fill(0,50000,'aa');
$array2 = array_fill(0,100,'bb');
// Test 1 (array_merge)
$start = microtime(true);
$r1 = array_merge($array1, $array2);
echo sprintf("Test 1: %.06f\n", microtime(true) - $start);
// Test2 (avoid copy)
$start = microtime(true);
foreach ($array2 as $v) {
$array1[] = $v;
}
echo sprintf("Test 2: %.06f\n", microtime(true) - $start);
// Test 1: 0.004963
// Test 2: 0.000038
Since PHP 7.4 you can use the ... operator. This is also known as the splat operator in other languages, including Ruby.
$parts = ['apple', 'pear'];
$fruits = ['banana', 'orange', ...$parts, 'watermelon'];
var_dump($fruits);
Output
array(5) {
[0]=>
string(6) "banana"
[1]=>
string(6) "orange"
[2]=>
string(5) "apple"
[3]=>
string(4) "pear"
[4]=>
string(10) "watermelon"
}
Splat operator should have better performance than array_merge. That’s not only because the splat operator is a language structure while array_merge is a function, but also because compile time optimization can be performant for constant arrays.
Moreover, we can use the splat operator syntax everywhere in the array, as normal elements can be added before or after the splat operator.
$arr1 = [1, 2, 3];
$arr2 = [4, 5, 6];
$arr3 = [...$arr1, ...$arr2];
$arr4 = [...$arr1, ...$arr3, 7, 8, 9];
Before PHP7 you can use:
array_splice($a, count($a), 0, $b);
array_splice() operates with reference to array (1st argument) and puts array (4th argument) values in place of list of values started from 2nd argument and number of 3rd argument. When we set 2nd argument as end of source array and 3rd as zero we append 4th argument values to 1st argument
if you want to merge empty array with existing new value. You must initialize it first.
$products = array();
//just example
for($brand_id=1;$brand_id<=3;$brand_id++){
array_merge($products,getByBrand($brand_id));
}
// it will create empty array
print_r($a);
//check if array of products is empty
for($brand_id=1;$brand_id<=3;$brand_id++){
if(empty($products)){
$products = getByBrand($brand_id);
}else{
array_merge($products,getByBrand($brand_id));
}
}
// it will create array of products
Hope its help.
foreach loop is faster than array_merge to append values to an existing array, so choose the loop instead if you want to add an array to the end of another.
// Create an array of arrays
$chars = [];
for ($i = 0; $i < 15000; $i++) {
$chars[] = array_fill(0, 10, 'a');
}
// test array_merge
$new = [];
$start = microtime(TRUE);
foreach ($chars as $splitArray) {
$new = array_merge($new, $splitArray);
}
echo microtime(true) - $start; // => 14.61776 sec
// test foreach
$new = [];
$start = microtime(TRUE);
foreach ($chars as $splitArray) {
foreach ($splitArray as $value) {
$new[] = $value;
}
}
echo microtime(true) - $start; // => 0.00900101 sec
// ==> 1600 times faster

Categories