PHP alter array with array_search and array_column - php

I have an array ($myArray) which I want to alter:
array(2) {
[0]=>
array(2) {
[0]=>
string(3) "100"
[1]=>
string(9) "fancyLink"
}
[1]=>
array(2) {
[0]=>
string(3) "200"
[1]=>
string(10) "fanyLink2"
}
}
I have two POST arrays which have the following structure.
First array $number:
array(2) {
[0]=>
string(3) "100"
[1]=>
string(3) "200"
}
and the second array $links:
array(2) {
[0]=>
string(12) "newFancyLink"
[1]=>
string(13) "newFancyLink2"
}
To alter the $myArray in order to replace one or more links according to the $number-value I wanted to use the following line
for($i = 0; $i < 2; $i++)
{
$myArray[array_search($number[$i], array_column($myArray, "0"))][1] = $links[$i];
}
But this does not work, it sets both links of 100 and 200 to the same value (the second link)
I wrote this code which works, but I would like to use the other line instead or at least compare the perfomance of it
for($i = 0; $i < 2; $i++)
{
for($j = 0; $j < 2; $j++)
{
if($myArray[$j][0] == $number[$i])
{
$myArray[$j][1] = $links[$i];
}
}
}
Using the $number-value as a key would make this a lot easier but this is not an option for me.
EDIT after Solving
In case anybody wants to know, both versions are alost identical fast. 10000 runs each result in this runtime:
0.10158801078796
0.10160994529724

Perhaps array_column($myArray, "0") should be array_column($myArray, 0) instead (since it is not an associative array)? That way it seems to work for me.
From the PHP-manual
array array_column ( array $input , mixed $column_key [, mixed $index_key = null ] )
column_key
The column of values to return. This value may be an integer key of the column you wish to retrieve, or it may be a string key name for an associative array or property name. It may also be NULL to return complete arrays or objects (this is useful together with index_key to reindex the array).

The solution using array_map and array_walk functions:
$numLinks = array_map(null, $number, $links);
// you may also iterate via a regular 'foreach' loop
array_walk($myArray, function(&$v, $k) use($numLinks){
if ($v[0] == $numLinks[$k][0]) $v[1] = $numLinks[$k][1];
});
print_r($myArray);
The output:
Array
(
[0] => Array
(
[0] => 100
[1] => newFancyLink
)
[1] => Array
(
[0] => 200
[1] => newFancyLink2
)
)

Related

Compare and remove from multidimensional array

I've got a multidimensional array as follows:
array(2) {
[0]=>
array(8) {
["id"]=>
string(3) "117"
["promotiontype_id"]=>
string(1) "1"
["groupa_id"]=>
string(3) "390"
["groupb_id"]=>
string(3) "390"
["varx"]=>
string(1) "2"
["vary"]=>
string(1) "1"
["varz"]=>
string(0) ""
["totaldiscount"]=>
float(6.5)
}
[1]=>
array(8) {
["id"]=>
string(3) "117"
["promotiontype_id"]=>
string(1) "1"
["groupa_id"]=>
string(3) "390"
["groupb_id"]=>
string(3) "390"
["varx"]=>
string(1) "2"
["vary"]=>
string(1) "1"
["varz"]=>
string(0) ""
["totaldiscount"]=>
float(7.0)
}
}
So, as you'll see, the first array has a "totaldiscount" of 6.5, the second has 7.0.
Essentially, I need to remove the array that contains the lowest value, so in this instance, it would be array [0] that gets removed as 6.5 has the lowest "totaldiscount". The array could contain more than 2 sub arrays.
I assume it's something to do with foreaching through, but my brain is going in to meltdown with this one!
Any help would be much appreciated!
I am going to divide your question in 2 parts:
How to find the lowest value of x?
function lowestX($array){
$lowest = 999;
for($array as $var){
if($lowest > $var["totaldiscount"]){
$lowest = $var["totaldiscount"];
}
}
}
How do I remove a value from an array?
Use unsset or function.array-splice
A possible solution is to use usort to sort the arrays by "totaldiscount"
Then get the lowest "totaldiscount" value from the sorted arrays.
Then you can loop the sorted arrays (in case there are multiple "totaldiscount" values which have the same lowest value) and unset the array(s) which contains the $lowestTotaldiscount by using the array key.
For example:
<?php
function cmp($a, $b)
{
return ($a["totaldiscount"] < $b["totaldiscount"]) ? -1 : 1;
}
usort($arrays, "cmp");
$lowestTotaldiscount = $arrays[0]["totaldiscount"];
foreach($arrays as $key => $array) {
if ($array["totaldiscount"] === $lowestTotaldiscount) {
unset($arrays[$key]);
}
}
Demo
here is solution of your problem .Simply use array_multisort & unset as given below .
`
$yourArray = array(
array(
"id"=>"117",
"promotiontype_id"=>"1",
"groupa_id"=>"390",
"groupb_id"=> "390",
"varx"=>"2",
"vary"=>"1",
"varz"=> "",
"totaldiscount"=>8.5,
),
array (
"id"=> "117",
"promotiontype_id"=>"1",
"groupa_id"=>"390",
"groupb_id"=>"390",
"varx"=>"2",
"vary"=>"1",
"varz"=>"",
"totaldiscount"=>7.0,
),
array (
"id"=> "117",
"promotiontype_id"=>"1",
"groupa_id"=>"390",
"groupb_id"=>"390",
"varx"=>"2",
"vary"=>"1",
"varz"=>"",
"totaldiscount"=>9.0, )
);
$discount = array();
foreach ($yourArray as $key => $row)
{
$discount[$key] = $row['totaldiscount'];
}
array_multisort($discount, SORT_ASC, $yourArray);
unset($yourArray[0]);
print"<pre>";
print_r($yourArray);`

Php array get all values that are repeating

I have a Php array that have values of times as array values and timestamps as key array is like this:
array(
144454884=>"12:00am", 145454884=>"12:30am", 144474884=>"1:00am", 144454864=>"1:30am", 143354884=>"1:00am", 144654884=>"1:30am", 1444567584=>"2:00am "
);
Timestamp values in above example are not real I wrote an example they are useless anyway unless your timezone matches mine.
Problem:
I need to get "1:00am" and "1:30am" twice I can get repeating values 1 time as shown in answer here:
php return only duplicated entries from an array
I need both repeating values two times with both keys and values being repeated because I need to eliminate those timestamps from week time on my system because of daylight saving a time is repeating and I don't want to show 1:00am at all I just want to show this time as unavailable.
I am not 100% sure what you wanted but this is what I think you need.
Assuming your input array is called $a
$b = array_flip(array_flip($a));
$c = array_diff_key($a, $b);
$b will contain an array of unique values.
$c will contain the elements that were removed.
Results of $b and $c are as follows:
array(5) {
[144454884] = string(7) "12:00am"
[145454884] = string(7) "12:30am"
[143354884] = string(6) "1:00am"
[144654884] = string(6) "1:30am"
[1444567584] = string(7) "2:00am "
}
array(2) {
[144474884] = string(6) "1:00am"
[144454864] = string(6) "1:30am"
}
This code works :
<?php
$array_new = [];
$array_tmp = [];
$array = array(1=>'1233',2=>'12334',3 =>'Hello' ,4=>'hello', 5=>'U');
//loop trough all elements in array and for ever element create key
//For "world" key is "world"
//For "World" key is "world"
//For "WORLD" key is "world"
//So all this cases have same key and differenet representation eg. "world" => ["world","World","WORLD"]
foreach($array as $k => $v){
$index = strtolower($v);
$array_tmp[$index][] = $v;
}
//loop trough new array with new keys and if there are more than one element(> 1) for some key, all of his representations put in new array
foreach($array_tmp as $k => $v){
if(count($v) > 1){
foreach($v as $k2 => $v2){
$array_new[] = $v2;
}
}
}
echo '<pre>';
print_r($array_new);
echo '<pre>';
A possible solution keeping the key information (I will assign the intermediate results to their own variables otherwise it can be confusing to read)
$array = array(
143354883 => "1:00am",
144454884 => "12:00am",
145454884 => "12:30am",
144474884 => "1:00am",
144454864 => "1:30am",
143354884 => "1:00am",
144654884 => "1:30am",
1444567584 => "2:00am ",
0 => 4,
1 => 4,
2 => 4,
3 => "Test",
4 => "TEST",
5 => "test "
);
// Used this array_iunique function: http://stackoverflow.com/questions/2276349/case-insensitive-array-unique
function array_iunique($array) {
return array_intersect_key(
$array,
array_unique(array_map("StrToLower",$array))
);
}
$unique = array_iunique($array);
// Then get the difference by key, that will give you all the duplicate values:
$diff_key = array_diff_key($array, $unique);
// Now we have to find the values that are in the $diff_key and the $unique because we also want to have those:
$correspondingValues = array_uintersect($unique, $diff_key, "strcasecmp");
// Then we have to combine the $duplicate values with the $diff_key and preserve the keys:
$result = array_replace($correspondingValues, $diff_key);
var_dump($result);
Will result in:
array(10) {
[143354883]=>
string(6) "1:00am"
[144454864]=>
string(6) "1:30am"
[0]=>
int(4)
[3]=>
string(4) "Test"
[144474884]=>
string(6) "1:00am"
[143354884]=>
string(6) "1:00am"
[144654884]=>
string(6) "1:30am"
[1]=>
int(4)
[2]=>
int(4)
[4]=>
string(4) "TEST"
}

Move some items to the end of the array if they fulfill a specific condition

I have an array of paths that I would like to sort ...
Array
(
/something/foo1
/something/special/foo2
/something/foo3
/something/special/foo4
/something/foo5
/something/special/foo6
)
... so that all paths that contain /special/ end up at the end of the array like this:
Array
(
/something/foo1
/something/foo3
/something/foo5
/something/special/foo2
/something/special/foo4
/something/special/foo6
)
The original sort order of paths must remain the same (so 1,2,3,4,5,6 => 1,3,5,2,4,6). Is there an elegant way to do this? Can this be implemented by using the usort function?
In your specific example, you can simply use asort($array);
But that is assuming foo is always foo.
Output:
array(6) {
[0]=>
string(15) "/something/foo1"
[2]=>
string(15) "/something/foo3"
[4]=>
string(15) "/something/foo5"
[1]=>
string(23) "/something/special/foo2"
[3]=>
string(23) "/something/special/foo4"
[5]=>
string(23) "/something/special/foo6"
}
If that's not the case, let me know and I'll do something else
... here is new method ref comment:
$array = array(
'/something/zoo',
'/something/special/foo',
'/something/loo',
'/something/special/goo',
'/something/boo',
'/something/special/poo'
);
uasort($array, function($a, $b) {
$specialInA = strpos($a, '/special/') !== false;
$specialInB = strpos($b, '/special/') !== false;
if ($specialInA > $specialInB) {
return 1;
}
if ($specialInB > $specialInA) {
return -1;
}
return $a > $b;
});
Output:
array(6) {
[4]=>
string(14) "/something/boo"
[2]=>
string(14) "/something/loo"
[0]=>
string(14) "/something/zoo"
[1]=>
string(22) "/something/special/foo"
[3]=>
string(22) "/something/special/goo"
[5]=>
string(22) "/something/special/poo"
}
Can probably be written better but should work
you can use unset and append [], like so
$x = array(1,2,3);
$x[] = $x[1];
unset($x[1]);
print_r($x);
Array
(
[0] => 1
[2] => 3
[3] => 2
)
You can thus loop over the array, test each element, and flip to the end the ones that contain the pattern.
$len = count($a);
for ($i=0; $i<$len; $i++) {
if (...) {
$a[] = $a[i];
unset($a[i]);
}
}
Edit: php's arrays are lists, hashes and arrays simultaneously. It is possible to move an element to the end while retaining its index! For example
$a = array(1,2,3);
$t = $a[1];
unset($a[1]);
$a[1] = $t;
print_r($a);
Array
(
[0] => 1
[2] => 3
[1] => 2
)

Turn flat array into nested array

Just working on something and can't find a simple solution to this problem without just looping through the array with a foreach. Does anyone have a simple solution for this
I want to turn this
&array(4) {
["a"]=>int(0)
["b"]=>int(1)
["c"]=>int(2)
["d"]=>int(3)
}
Into this
array(1) {
["a"]=>
array(1) {
[0]=>
array(1) {
["b"]=>
array(1) {
[0]=>
array(1) {
["c"]=>
array(1) {
[0]=>
array(1) {
["d"]=> int(1) //this value does not matter
}
}
}
}
}
}
}
The values don't matter at all I just need the keys to run against a array_intersect_key_recursive function that I have.
EDIT : The array has changed after testing it needs to be nested as an array of an array
I don't know how this could possibly end up helping you, but it was a fun exercise nonetheless.
$newArray = array();
$last = &$newArray;
$array = array_reverse(array_keys($array));
while ($item = array_pop($array)) {
if (!is_array($last)) {
$last = array();
}
$last[$item] = array(array());
$last = &$last[$item][0];
}
NOTE: I made this answer with the int(1). You said the value is not important so I'm not going to bother changing it for now, but you would have to do a bit more work if the value was important (probably something like get the value from the original array with $item as the key).
Another approach using recursion:
function toNestedArray(array $array, $index = 0) {
$return = array();
if ($index < count($array)) {
$return[$array[$index]] = toNestedArray($array, ++$index);
}
return $return;
}
Usage Example:
$flatArray = array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4);
$nestedArray = toNestedArray(array_keys($flatArray));
print_r($nestedArray);
Output:
Array
(
[a] => Array
(
[b] => Array
(
[c] => Array
(
[d] => Array
(
)
)
)
)
)

PHP - How to move the empty values of an array to its last positions

How can I move the empty values of an array to its last position?
For example:
$givenArray = array(
0=>'green',
1=>'',
2=>'red',
3=>'',
4=>'blue'
);
$requiredArray = array(
0=>'green',
1=>'red',
2=>'blue',
3=>'',
4=>''
);
Provided that the non empty values should not be sorted. It should be as it is, i.e. only the empty values should move to the end of an array.
I need exactly what my examples show.
You are looking for all values not being an empty string ("") first and then all values being an empty string:
$requiredArray = array_diff($givenArray, array(''))
+ array_intersect($givenArray, array(''));
This will give you:
array(5) {
[0]=> string(5) "green"
[2]=> string(3) "red"
[4]=> string(4) "blue"
[1]=> string(0) ""
[3]=> string(0) ""
}
Which has the benefit that it preserves key => value association. If you need to renumber the keys, just apply the array_values function:
$requiredArray = array_values($requiredArray);
This will turn it into your required layout (Demo):
array(5) {
[0]=> string(5) "green"
[1]=> string(3) "red"
[2]=> string(4) "blue"
[3]=> string(0) ""
[4]=> string(0) ""
}
There are much better/more elegant answers in this thread already, but this works too:
//strip empties and move to end
foreach ($givenArray as $key => $value)
{
if ($value === "")
{
unset($givenArray[$key]);
$givenArray[] = $value;
}
}
// rebuild array index
$givenArray = array_values($givenArray);
Codepad demo
Try using usort.
function empty_sort ($a, $b) {
if ($a == '' && $b != '') return 1;
if ($b == '' && $a != '') return -1;
return 0;
}
usort($array, 'empty_sort');
Which gives (Demo):
Array
(
[0] => blue
[1] => green
[2] => red
[3] =>
[4] =>
)
This should work:
function sortempty( $a, $b ) {
return empty( $a );
}
usort( $array, 'sortempty' );
Output (Demo):
Array
(
[0] => blue
[1] => green
[2] => red
[3] =>
[4] =>
)
usort() allows you to sort an array using a user-defined function. I return if $a is empty or not. If it's empty, return 1 which makes value $a shift right (or down) in the array.
$givenArray = array(
0=>'green',
1=>'',
2=>'red',
3=>'',
4=>'blue'
);
foreach($givenArray as $value){
if(empty($value)){
$newarray[] = $value;
}else{
$filledarray[] = $value;
}
}
$requiredArray = array_merge($filledarray,$newarray);
There is usort($array, $callback) function that will sort with your own custom callback.

Categories