Array slice like hash slice in perl - php

Is there built-in function, or shorter way to extract elements into new array, as described here?
<?php
function arr_slice ($arr, $keys) {
$ret = array();
foreach ($keys as $k) { $ret[$k] = $arr[$k]; }
return $ret;
}
$array = array(
"a" => 1,
"b" => 2,
"c" => 3,
"d" => 4,
);
var_export(
arr_slice($array, array("x","d","b"))
);
output (key order matters)
array (
'x' => NULL,
'd' => 4,
'b' => 2,
)

Related

Array Keys Comparison Without In-Build Function

I am having two arrays of key-value pairs.
Arrays as follows:
$array1 = ["a" => 2, "b" => 3, "c" => 1, "d" => 2];
$array2 = ["c" => 1, "d" => 1, "a" => 2, "b" => 3, "x" => 4, "z" => 1];
Problem Statement
I need to find the count of the number of keys of array1 present in array2 having the same value.
Example
Count will be 3 as keys a, b, and c of array1 are present in array2 and having same values 2, 3, and 1 respectivily.
Tried method
foreach($array1 as $key => $value){
if($array2.$key === $array1.$key){
if($array2[$value] === $array1[$value]){
$matchCount++;
}
}
}
NOTE: I am not sure about accessing the keys from the array object, so using dot(.), somehow I am getting the count, but not correct count.
<?php
$array1 = ["a" => 2, "b" => 3, "c" => 1, "d" => 2];
$array2 = ["c" => 1, "d" => 1, "a" => 2, "b" => 3, "x" => 4, "z" => 1];
$count = 0;
foreach($array1 as $key => $value){
$array_2_value = $array2[$key] ?? null;
if($array_2_value !== null && $array_2_value === $value) $count++;
}
echo $count;
Demo: https://3v4l.org/BREbg
You can just loop over $array1 and check if the key exists in $array2 with the same value. If yes, we increment count. You can make use of null coalescing operator ?? to check if the $key exists in $array2 or not.
function countSameKeyAndValues(array $array1, array $array2): int
{
$sameKeys = array_keys(array_intersect($array1, $array2));
$count = 0;
foreach ($sameKeys as $key) {
if ($array1[$key] === $array2[$key]) {
$count++;
}
}
return $count;
}
You can loop over the $array1 using foreach loop.
Then you can check for the values of $array2 using the key for $array1.
Then if value exist for that key, you can check if value is same at that of $array1
<?php
$array1 = ["a" => 2, "b" => 3, "c" => 1, "d" => 2];
$array2 = ["c" => 1, "d" => 1, "a" => 2, "b" => 3, "x" => 4, "z" => 1];
$count = 0;
foreach($array1 as $key => $value){
$array2Value = $array2[$key] ?? null;
if($array2Value !== null && $array2Value === $value)
$count++;
}
echo $count;

PHP - More efficient method for sorting alphanumeric keys

NOTE: I edited the example and replaced all values with 1. The values do not matter, only the keys do. The previous values I had written led to a misunderstanding. Sorry.
NOTE: a/b blocks are always continuous. I'm adding this because it wasn't clear. If there is 3a/3b and 5a/5b there will always be 4a/4b and not only 4.
I have arrays that contain numbered keys with leading zeros. Sometimes, these numbered keys have two variations that I distinguish by using the suffixes a and b. The number of keys with or without variations is unknown, however there is never more than 2 digits; i.e. the highest numerical key is '09'.
The problem is that these array keys need to be sorted numerically, but when suffixes are present, those should take precedence. Using ksort() alone does not achieve this.
For example, ksort() gives me this:
$arr = array(
'01' => 1,
'02' => 1,
'03a' => 1,
'03b' => 1,
'04a' => 1,
'04b' => 1,
'05a' => 1,
'05b' => 1,
'06' => 1,
);
But, I need this:
$arr = array(
'01' => 1,
'02' => 1,
'03a' => 1,
'04a' => 1,
'05a' => 1,
'03b' => 1,
'04b' => 1,
'05b' => 1,
'06' => 1,
);
I use some fancy coding gymnastics to get what I want, but it isn't pretty. I'm wondering if there's a better, cleaner way?
Here is what I do.
1) I use ksort() which gives me the first of the two arrays above. (The one which isn't yet what I want.)
2) I create two arrays. One for the 'a' suffixes, the other for the 'b' suffixes.
$arr_a = array();
$arr_b = array();
foreach ($arr as $k => $v) {
if (substr($k, 2) == 'a') {
$arr_a[$k] = $v;
} else if (substr($k, 2) == 'b') {
$arr_b[$k] = $v;
}
}
3) I merge the two suffix arrays.
$arr_suffixes = array_merge($arr_a, $arr_b);
4) I slice up my original array so that I get the part before the suffixes, and the part after the suffixes.
$i = array_search(key($arr_suffixes), array_keys($arr));
$length = count($arr_suffixes);
$arr_before_suffixes = array_slice($arr, 0, $i);
$arr_after_suffixes = array_slice($arr, $i + $length);
5) Using array_merge, I recombine the sliced arrays to create the array I need.
$arr = array_merge($arr_before_suffixes, $arr_suffixes);
$arr = array_merge($arr, $arr_after_suffixes);
Finally, we have the correct $arr. Isn't there a better way to do this? It feels really ugly.
You have no formalized rule. I'll try to guess.
$arr = array(
'01' => 1,
'02' => 1,
'03a' => 1,
'03b' => 1,
'04a' => 1,
'04b' => 1,
'05a' => 1,
'05b' => 1,
'06' => 1,
);
uksort($arr, function($item1, $item2)
{
$last1 = substr($item1, -1);
$last2 = substr($item2, -1);
// one of the items is a number or last letters matches
if (is_numeric($last1) || is_numeric($last2) || $last1 == $last2)
// simple number comparison
return $item1 - $item2;
else
// natural order comparison
return $last1 > $last2 ? 1 : -1;
});
var_dump($arr);
natsort() function will helps you:
$arr = array(
'01' => 1,
'02' => 1,
'03a' => 1,
'03b' => 1,
'04a' => 1,
'04b' => 1,
'05a' => 1,
'05b' => 1,
'06' => 1,
);
$keys = array_keys($arr);
natsort($keys);
$result = array();
foreach ($keys as $key) {
$result[$key] = $arr[$key];
}
print_r($result); // Your expected result
$arr = array(
'01' => 1,
'02' => 2,
'03a' => 3,
'03b' => 6,
'04a' => 4,
'04b' => 7,
'05a' => 5,
'05b' => 8,
'06' => 9,
);
uksort(
$arr,
function($a, $b) {
sscanf($a, '%d%s', $an, $as);
sscanf($b, '%d%s', $bn, $bs);
if ($as === null || $bs === null || $as === $bs) {
return $an - $bn;
}
return strcmp($as, $bs);
}
);
var_dump($arr);

add the values of two different associative arrays in php . display unique key-values too in the result array [duplicate]

This question already has answers here:
How to sum all column values in multi-dimensional array?
(20 answers)
Closed 9 years ago.
i need to merge two associative arrays which may or may not contain same key,if key is same the values need to added and stored in the resultant array
$array1 = array(
'a' => 5,
'b' => 10,
'c' => 6,
'k' = > 10
);
$array2 = array(
'a' => 100,
'c' => 200,
'd' => 30,
'k' => 10
);
how to add the above two associative arrays and receive the following output/associative array -
$array2 = array(
'a' => 105,
'b' => 10,
'c' => 206,
'd' => 30,
'k' => 20
);
Try
$array1 = array(
'a' => 5,
'b' => 10,
'c' => 6,
'k' => 10
);
$array2 = array(
'a' => 100,
'c' => 200,
'd' => 30,
'k' => 10
);
$sums = array();
foreach (array_keys($array1 + $array2) as $key) {
$sums[$key] = (isset($array1[$key]) ? $array1[$key] : 0) + (isset($array2[$key]) ? $array2[$key] : 0);
}
print_r($sums);
$a3 = array_merge_recursive ($array1, $array2);
foreach ($a3 as $key => $value)
{
$a3[$key] = (is_array($value))?array_sum($value):$value;
}
for finding unique index value
$array2 =array_merge($array1,$array2);
and for finding unique value you can try
$array2 =array_unique(array_merge($array1,$array2));
I don't know if you can do this with an internal function but it is doable by simply iterating through both arrays.
function merge_add($array1, $array2)
{
$result = array();
merge_add_array($array1, $result);
merge_add_array($array2, $result);
return $result;
}
function merge_add_array($array, &$result)
{
foreach ($array as $key=>$value)
{
if (array_key_exists($key, $result))
{
$result[$key] += $value;
}
else
{
$result[$key] = $value;
}
}
}
$result = merge_add($array1, $array2);
The & will cause passing by reference
<?php
$array1 = array(
'a' => 5,
'b' => 10,
'c' => 6,
'k' => 10
);
$array2 = array(
'a' => 100,
'c' => 200,
'd' => 30,
'k' => 10
);
$keys = array_keys($array1 + $array2);
foreach ($keys as $key) {
$array2[$key] = isset($array1[$key]) && isset($array2[$key]) ? ($array1[$key] + $array2[$key]) : (isset($array1[$key]) ? $array1[$key] : $array2[$key]);
}
print_r($array2);

php -Merging an Array

I have two array which i want to merge in a specific way in php.
So i need your help in helping me with it as i tried and failed.
So say i have two arrays:
$array1= array(
"foo" => 3,
"bar" => 2,
"random1" => 4,
);
$array2= array(
"random2" => 3,
"random3" => 4,
"foo" => 6,
);
Now when during merging i would like the common key's values to be added.
So like foo exists in array1 and in array2 so when merging array1 with array 2 i should get "foo" => "9"
I better illustration would be the final array which looks like this:
$array1= array(
"foo" => 9,
"bar" => 2,
"random1" => 4,
"random2" => 3,
"random3" => 4,
);
So again i would like the values of the common keys to be added together and non common keys to be added to array or a new array
I hope i was clear enough
Thanks,
Vidhu
Something like that:
function mergeValues() {
$result = array();
$arraysToMerge = func_get_args();
foreach ($arraysToMerge as $array) {
foreach($array as $key => $value) {
$result[$key] += $value;
}
}
return $result;
}
$res = mergeValues($array1, $array2, $array3); // Can pass any ammount of arrays to a function.
foreach($array1 as $k => $v)
{
If (isset($array2[$k]))
$array1[$k] += $array2[$k];
}
foreach($array2 as $k => $v)
{
If (!isset($array1[$k]))
$array1[$k] = $array2[$k];
}

How to add an array value to the middle of an associative array?

Lets say I have this array:
$array = array('a'=>1,'z'=>2,'d'=>4);
Later in the script, I want to add the value 'c'=>3 before 'z'. How can I do this?
Yes, the order is important. When I run a foreach() through the array, I do NOT want this newly added value added to the end of the array. I am getting this array from a mysql_fetch_assoc()
The keys I used above are placeholders. Using ksort() will not achieve what I want.
http://www.php.net/manual/en/function.array-splice.php#88896 accomplishes what I'm looking for but I'm looking for something simpler.
Take a sample db table with about 30 columns. I get this data using mysql_fetch_assoc(). In this new array, after column 'pizza' and 'drink', I want to add a new column 'full_dinner' that combines the values of 'pizza' and 'drink' so that when I run a foreach() on the said array, 'full_dinner' comes directly after 'drink'
Am I missing something?
$key = 'z';
$offset = array_search($key, array_keys($array));
$result = array_merge
(
array_slice($array, 0, $offset),
array('c' => 3),
array_slice($array, $offset, null)
);
Handling of nonexistent keys (appending $data by default):
function insertBeforeKey($array, $key, $data = null)
{
if (($offset = array_search($key, array_keys($array))) === false) // if the key doesn't exist
{
$offset = 0; // should we prepend $array with $data?
$offset = count($array); // or should we append $array with $data? lets pick this one...
}
return array_merge(array_slice($array, 0, $offset), (array) $data, array_slice($array, $offset));
}
Demo:
$array = array('a' => 1, 'z' => 2, 'd' => 4);
// array(4) { ["a"]=> int(1) ["c"]=> int(3) ["z"]=> int(2) ["d"]=> int(4) }
var_dump(insertBeforeKey($array, 'z', array('c' => 3)));
// array(4) { ["a"]=> int(1) ["z"]=> int(2) ["d"]=> int(4) ["c"]=> int(3) }
var_dump(insertBeforeKey($array, 'y', array('c' => 3)));
A simple approach to this is to iterate through the original array, constructing a new one as you go:
function InsertBeforeKey( $originalArray, $originalKey, $insertKey, $insertValue ) {
$newArray = array();
$inserted = false;
foreach( $originalArray as $key => $value ) {
if( !$inserted && $key === $originalKey ) {
$newArray[ $insertKey ] = $insertValue;
$inserted = true;
}
$newArray[ $key ] = $value;
}
return $newArray;
}
Then simply call
$array = InsertBeforeKey( $array, 'd', 'c', 3 );
According to your original question the best answer I can find is this:
$a = array('a'=>1,'z'=>2,'d'=>4);
$splitIndex = array_search('z', array_keys($a));
$b = array_merge(
array_slice($a, 0, $splitIndex),
array('c' => 3),
array_slice($a, $splitIndex)
);
var_dump($b);
array(4) {
["a"]=>
int(1)
["c"]=>
int(3)
["z"]=>
int(2)
["d"]=>
int(4)
}
Depending on how big your arrays are you will duplicate quite some data in internal memory, regardless if you use this solution or another.
Furthermore your fifth edit seems to indicate that alternatively your SQL query could be improved. What you seem to want to do there would be something like this:
SELECT a, b, CONCAT(a, ' ', b) AS ab FROM ... WHERE ...
If changing your SELECT statement could make the PHP solution redundant, you should definitely go with the modified SQL.
function insertValue($oldArray, $newKey, $newValue, $followingKey) {
$newArray = array ();
foreach (array_keys($oldArray) as $k) {
if ($k == $followingKey)
$newArray[$newKey] = $newValue;
$newArray[$k] = $oldArray [$k];
}
return $newArray;
}
You call it as
insertValue($array, 'c', '3', 'z')
As for Edit 5:
edit your sql, so that it reads
SELECT ..., pizza, drink, pizza+drink as full_meal, ... FROM ....
and you have the column automatically:
Array (
...
'pizza' => 12,
'drink' => 5,
'full_meal' => 17,
...
)
Associative arrays are not ordered, so you can simply add with $array['c'] = 3.
If order is important, one option is switch to a data structure more like:
$array = array(
array('a' => 1),
array('b' => 2)
array('d' => 4)
);
Then, use array_splice($array, 2, 0, array('c' => 3)) to insert at position 2. See manual on array_splice.
An alternative approach is to supplement the associative array structure with an ordered index that determines the iterative order of keys. For instance:
$index = array('a','b','d');
// Add new value and update index
$array['c'] = 3;
array_splice($index, 2, 0, 'c');
// Iterate the array in order
foreach $index as $key {
$value = $array[$key];
}
You can define your own sortmap when doing a bubble-sort by key. It's probably not terribly efficient but it works.
<pre>
<?php
$array = array('a'=>1,'z'=>2,'d'=>4);
$array['c'] = 3;
print_r( $array );
uksort( $array, 'sorter' );
print_r( $array );
function sorter( $a, $b )
{
static $ordinality = array(
'a' => 1
, 'c' => 2
, 'z' => 3
, 'd' => 4
);
return $ordinality[$a] - $ordinality[$b];
}
?>
</pre>
Here's an approach based on ArrayObject using this same concept
$array = new CitizenArray( array('a'=>1,'z'=>2,'d'=>4) );
$array['c'] = 3;
foreach ( $array as $key => $value )
{
echo "$key: $value <br>";
}
class CitizenArray extends ArrayObject
{
static protected $ordinality = array(
'a' => 1
, 'c' => 2
, 'z' => 3
, 'd' => 4
);
function offsetSet( $key, $value )
{
parent::offsetSet( $key, $value );
$this->uksort( array( $this, 'sorter' ) );
}
function sorter( $a, $b )
{
return self::$ordinality[$a] - self::$ordinality[$b];
}
}
For the moment the best i can found to try to minimize the creation of new arrays are these two functions :
the first one try to replace value into the original array and the second one return a new array.
// replace value into the original array
function insert_key_before_inplace(&$base, $beforeKey, $newKey, $value) {
$index = 0;
foreach($base as $key => $val) {
if ($key==$beforeKey) break;
$index++;
}
$end = array_splice($base, $index, count($base)-$index);
$base[$newKey] = $value;
foreach($end as $key => $val) $base[$key] = $val;
}
$array = array('a'=>1,'z'=>2,'d'=>4);
insert_key_before_inplace($array, 'z', 'c', 3);
var_export($array); // array ( 'a' => 1, 'c' => 3, 'z' => 2, 'd' => 4, )
// create new array
function insert_key_before($base, $beforeKey, $newKey, $value) {
$index = 0;
foreach($base as $key => $val) {
if ($key==$beforeKey) break;
$index++;
}
$end = array_splice($base, $index, count($base)-$index);
$base[$newKey] = $value;
return $base+$end;
}
$array = array('a'=>1,'z'=>2,'d'=>4);
$newArray=insert_key_before($array, 'z', 'c', 3);
var_export($array); // ( 'a' => 1, 'z' => 2, 'd' => 4, )
var_export($newArray); // array ( 'a' => 1, 'c' => 3, 'z' => 2, 'd' => 4, )
function putarrayelement(&$array, $arrayobject, $elementposition, $value = null) {
$count = 0;
$return = array();
foreach ($array as $k => $v) {
if ($count == $elementposition) {
if (!$value) {
$value = $count;
}
$return[$value] = $arrayobject;
$inserted = true;
}
$return[$k] = $v;
$count++;
}
if (!$value) {
$value = $count;
}
if (!$inserted){
$return[$value];
}
$array = $return;
return $array;
}
$array = array('a' => 1, 'z' => 2, 'd' => 4);
putarrayelement($array, '3', 1, 'c');
print_r($array);
Great usage of array functions but how about this as a simpler way:
Add a static column to the SQL and then replace it in the resultant array. Order stays the same:
SQL :
Select pizza , drink , 'pizza-drink' as 'pizza-drink' , 28 columns..... From Table
Array :
$result['pizza-drink'] = $result['pizza'] . $result['drink'];
A simplified Alix Axel function if you need to just insert data in nth position:
function array_middle_push( array $array, int $position, array $data ): array {
return array_merge( array_slice( $array, 0, $position ), $data, array_slice( $array, $position ) );
}
Try this
$array['c']=3;
An associative array is not ordered by default, but if you wanted to sort them alphabetically you could use ksort() to sort the array by it's key.
If you check out the PHP article for ksort() you will se it's easy to sort an array by its key, for example:
<?php
$fruits = array("d"=>"lemon", "a"=>"orange", "b"=>"banana", "c"=>"apple");
ksort($fruits);
foreach ($fruits as $key => $val) {
echo "$key = $val\n";
}
?>
// The above example will output:
a = orange
b = banana
c = apple
d = lemon
you can add it by doing
$array['c']=3;
and if you absolutely want it sorted for printing purposes, you can use php's ksort($array) function
if the keys are not sortable by ksort, then you will have to create your own sort by using php's uasort function. see examples here
http://php.net/manual/en/function.uasort.php

Categories