I have an array:
Array(
[0] => Array(
['title'] => 'Apple',
['type'] => '1'
),
[1] => Array(
['title'] => 'Oranage',
['type'] => '2'
),
[2] => Array(
['title'] => 'Tomato',
['type'] => '1'
),
//when compares with [0], 'type' is equal and both contains 'Apple', remove.
[3] => Array(
['title'] => 'Red Apple',
['type'] => '1'
),
[4] => Array(
['title'] => 'Big Tomato',
['type'] => '3'
),
//when compares with [1], 'type' is equal and both contains 'Oranage', remove.
[5] => Array(
['title'] => 'Sweet Oranage',
['type'] => '2'
)
);
If the 'type' element is equal, while 'title' elment contains the same string ([0] and [3] contains 'Apple'), then only one element will be used.
The result will be:
Array(
[0] => Array(
['title'] => 'Apple',
['type'] => '1'
),
[1] => Array(
['title'] => 'Oranage',
['type'] => '2'
),
[2] => Array(
['title'] => 'Tomato',
['type'] => '1'
),
[4] => Array(
['title'] => 'Big Tomato',
['type'] => '3'
)
);
How to filter this, I am so confused.
Thanks.
If you consider your conditions as alternative, then if passing one of the following criteria, only one of all the values meeting specific criteria can be used:
the 'type' element is equal,
the 'title' element in each second level array are the same ([2] and [5]), or
one 'title' element contains another([0] and [3]),
If so, you can just use some indexing arrays for storing already found 'type' and 'title' variables and:
add one variable,
check whether the next variable:
has 'type' already in the index table,
has 'title' already in the index,
is contained in 'title' already defined in index or contains 'title' already defined in index,
if 2. shows that at least one of the criteria is met, do not add it to the result, otherwise add it,
go to point 2.
In the return you should receive what you described. Just write it in PHP.
Something like this should do:
$array = array(/* your array */);
$filteredArray = array();
foreach ($array as $key => $elem) {
foreach ($filteredArray as $comp) {
if ($elem['type'] == $comp['type'] &&
(strpos($elem['title'], $comp['title']) !== false || strpos($comp['title'], $elem['title']) !== false)
) {
continue 2; // skip to the next $elem
}
}
$filteredArray[$key] = $elem;
}
If the array is held in variable $ar, then:
$filtered = Array();
for(int $i = 0; $i < count($ar); $i++) {
for(int $j = $i; $j < count($ar); $j++) {
if($ar[$i][$type] == $ar[$i][$type]) {
if(strlen($ar[$i][$title]) < strlen($ar[$j][$title])) {
$larger = $j;
$smaller = $i;
}
else {
$larger = $i;
$smaller = $j;
}
if(preg_match(strtolower($smaller), strtolower($larger)) {
$filtered = array_merge($filtered, array_slice($ar, 0, $larger - 1), array_slice($ar, $larger, count($ar) - $larger));
}
}
}
}
Finds two elements with equal types. Then, take the title of the element with the shortest title, and search through the other element for a preg_match. If found, merge the previous filtered array with all of the elements before and after the duplicate.
Related
This question already has answers here:
Sorting a php array of arrays by custom order
(8 answers)
Closed 28 days ago.
I have array $data containing data about animals. I would like to sort this array by child element:
source array ($data):
Array (
[0] => (
'name' => 'Leo'
'type' => 'cat'
)
[1] => (
'name' => 'Max'
'type' => 'dog'
)
[2] => (
'name' => 'Elsa'
'type' => 'fish'
)
...
)
priority array ($priority)
$priority = [
'fish', 'dog', 'cat',
];
I would like to sort source array using priority array. I tried:
sort($data, function (int $item1, int $item2) use($priority) {
foreach($priority as $key => $value) {
if($item1 == $value)
{
return 0;
break;
}
if($item2 == $value)
{
return 1;
break;
}
}
return 0;
});
You can use usort with a custom compare function, like so:
<?php
$arr = array(
0 => array(
'name' => 'Leo',
'type' => 'cat'
),
1 => array(
'name' => 'Max',
'type' => 'dog'
),
2 => array(
'name' => 'Elsa',
'type' => 'fish'
)
);
$priority = array('fish', 'dog', 'cat');
usort($arr, function($a, $b) use($priority) {
return array_search($a['type'], $priority) <=> array_search($b['type'], $priority);
});
var_dump($arr);
How this works:
usort accepts a custom compare function, you can pass it the priority array, then use the spaceship operator to compare the value indexes in priority.
Try it out: http://sandbox.onlinephpfunctions.com/code/03fdfa61b1bd8b0b84e5f08ab11b6bc90eeaef4a
I have an array of arrays, as such
$statuses = array(
[0] => array('id'=>10, 'status' => 'active'),
[1] => array('id'=>11, 'status' => 'closed'),
[2] => array('id'=>12, 'status' => 'active'),
[3] => array('id'=>13, 'status' => 'stopped'),
)
I want to be able to make a new array of arrays and each of those sub arrays would contain the elements based on if they had the same status.
The trick here is, I do not want to do a case check based on hard coded status names as they can be random. I want to basically do a dynamic comparison, and say "if you are unique, then create a new array and stick yourself in there, if an array already exists with the same status than stick me in there instead". A sample result could look something like this.
Ive really had a challenge with this because the only way I can think to do it is check every single element against every other single element, and if unique than create a new array. This gets out of control fast if the original array is larger than 100. There must be some built in functions that can make this efficient.
<?php
$sortedArray = array(
['active'] => array(
array(
'id' => 10,
'status' => 'active'
),
array(
'id' => 12,
'status' => 'active'
)
),
['closed'] => array(
array(
'id' => 11,
'status' => 'active'
)
),
['stopped'] => array(
array(
'id' => 13,
'status' => 'active'
)
),
)
$SortedArray = array();
$SortedArray['active'] = array();
$SortedArray['closed'] = array();
$SortedArray['stopped'] = array();
foreach($statuses as $Curr) {
if ($Curr['status'] == 'active') { $SortedArray['active'][] = $Curr; }
if ($Curr['status'] == 'closed') { $SortedArray['closed'][] = $Curr; }
if ($Curr['status'] == 'stopped') { $SortedArray['stopped'][] = $Curr; }
}
You can also do it with functional way though it's pretty the same like Marc said.
$sorted = array_reduce($statuses, function($carry, $status) {
$carry[$status['status']][] = $status;
return $carry;
}, []);
when searching an element in a nested array, could i get back it's 1st level nesting index.
<?php
static $cnt = 0;
$name = 'victor';
$coll = array(
'dep1' => array(
'fy' => array('john', 'johnny', 'victor'),
'sy' => array('david', 'arthur'),
'ty' => array('sam', 'joe', 'victor')
),
'dep2' => array(
'fy' => array('natalie', 'linda', 'molly'),
'sy' => array('katie', 'helen', 'sam', 'ravi', 'vipul'),
'ty' => array('sharon', 'julia', 'maddy')
)
);
function recursive_search(&$v, $k, $search_query){
global $cnt;
if($v == $search_query){
/* i want the sub array index to be returned */
}
}
?>
i.e to say, if i'am searching 'victor', i would like to have 'dep1' as the return value.
Could anyone help ??
Try:
$name = 'victor';
$coll = array(
'dep1' => array(
'fy' => array('john', 'johnny', 'victor'),
'sy' => array('david', 'arthur'),
'ty' => array('sam', 'joe', 'victor')
),
'dep2' => array(
'fy' => array('natalie', 'linda', 'molly'),
'sy' => array('katie', 'helen', 'sam', 'ravi', 'vipul'),
'ty' => array('sharon', 'julia', 'maddy')
)
);
$iter = new RecursiveIteratorIterator(new RecursiveArrayIterator($coll), RecursiveIteratorIterator::SELF_FIRST);
/* These will be used to keep a record of the
current parent element it's accessing the childs of */
$parent_index = 0;
$parent = '';
$parent_keys = array_keys($coll); //getting the first level keys like dep1,dep2
$size = sizeof($parent_keys);
$flag=0; //to check if value has been found
foreach ($iter as $k=>$val) {
//if dep1 matches, record it until it shifts to dep2
if($k === $parent_keys[$parent_index]){
$parent = $k;
//making sure the counter is not incremented
//more than the number of elements present
($parent_index<$size-1)?$parent_index++:'';
}
if ($val == $name) {
//if the value is found, set flag and break the loop
$flag = 1;
break;
}
}
($flag==0)?$parent='':''; //this means the search string could not be found
echo 'Key = '.$parent;
Demo
This works , but I don't know if you are ok with this...
<?php
$name = 'linda';
$col1=array ( 'dep1' => array ( 'fy' => array ( 0 => 'john', 1 => 'johnny', 2 => 'victor', ), 'sy' => array ( 0 => 'david', 1 => 'arthur', ), 'ty' => array ( 0 => 'sam', 1 => 'joe', 2 => 'victor', ), ), 'dep2' => array ( 'fy' => array ( 0 => 'natalie', 1 => 'linda', 2 => 'molly', ), 'sy' => array ( 0 => 'katie', 1 => 'helen', 2 => 'sam', 3 => 'ravi', 4 => 'vipul', ), 'ty' => array ( 0 => 'sharon', 1 => 'julia', 2 => 'maddy', ), ), );
foreach($col2 as $k=>$arr)
{
foreach($arr as $k1=>$arr2)
{
if(in_array($name,$arr2))
{
echo $k;
break;
}
}
}
OUTPUT :
dept2
Demo
What I'd like to do is have a function that accepts two arguments, both arrays, the first being a one-dimensional array of varying lengths and the second is a multi-dimensional array of varying depths and lengths. The first array is never associative, the second is always a fully associative array.
This function would return the requested value from the multi-dimensional array as indicated by the first array.
Assume that the first array will always be hand-written and passed to this function. Meaning the developer always knows there is a value to be returned from the multi-dimensional array and would never pass a request to the function where a value did not exist.
I think the code below is the best example at what I'm trying to achieve.
//Example multi-dimensional array
$multi = array(
'fruit' => array(
'red' => array(
'strawberries' => '$2.99/lb',
'apples' => '$1.99/lb'
),
'green' => array(
'honeydew' => '$3.39/lb',
'limes' => '$0.75/lb'
)
),
'vegetables' => array(
'yellow' => array(
'squash' => '$1.29/lb',
'bellpepper' => '$0.99/lb'
),
'purple' => array(
'eggplant' => '$2.39/lb'
)
),
'weeklypromo' => '15% off',
'subscribers' => array(
'user1#email.com' => 'User 1',
'user2#email.com' => 'User 2',
'user3#email.com' => 'User 3',
'user4#email.com' => 'User 4'
)
);
//Example one-dimensional array
$single = array('fruit', 'red', 'apples');
function magicfunc($single, $multi) {
//some magic here that looks something like below
$magic_value = $multi[$single[0]][$single[1]][$single[2]];
return $magic_value;
}
//Examples:
print magicfunc(array('fruit', 'red', 'apples'), $multi);
Output:
$1.99/lb
print magicfunc(array('subscribers', 'user3#email.com'), $multi);
Output:
User 3
print magicfunc(array('weeklypromo'), $multi);
Output:
15% off
This returns the values as requested:
function magicfunc($single, $multi) {
while (true) {
if (!$single) {
break;
}
$searchIndex = array_shift($single);
foreach ($multi as $k => $val) {
if ($k == $searchIndex) {
$multi = $val;
continue 2;
}
}
}
return $multi;
}
I have an array of items:
array(
[0] => array(
'item_no' => 1
'item_name' => 'foo
)
[1] => array(
'item_no' => 2
'item_name' => 'bar'
)
) etc. etc.
I am getting another array from a third party source and need to remove items that are not in my first array.
array(
[0] => array(
'item_no' => 1
)
[1] => array(
'item_no' => 100
) # should be removed as not in 1st array
How would I search the first array using each item in the second array like (in pseudo code):
if 'item_no' == x is in 1st array continue else remove it from 2nd array.
// Returns the item_no of an element
function get_item_no($arr) { return $arr['item_no']; }
// Arrays of the form "item_no => position in the array"
$myKeys = array_flip(array_map('get_item_no', $myArray));
$theirKeys = array_flip(array_map('get_item_no', $theirArray));
// the part of $theirKeys that has an item_no that's also in $myKeys
$validKeys = array_key_intersect($theirKeys, $myKeys);
// Array of the form "position in the array => item_no"
$validPos = array_flip($validKeys);
// The part of $theirArray that matches the positions in $validPos
$keptData = array_key_intersect($theirArray, $validPos);
// Reindex the remaining values from 0 to count() - 1
return array_values($keptData);
All of this would be easier if, instead of storing the key in the elements, you stored it as the array key (that is, you'd be using arrays of the form "item_no => item_data") :
// That's all there is to it
return array_key_intersect($theirArray, $myArray);
You can also do:
$my_array =array(
0 => array( 'item_no' => 1,'item_name' => 'foo'),
1 => array( 'item_no' => 2,'item_name' => 'bar')
);
$thrid_party_array = array(
0 => array( 'item_no' => 1),
1 => array( 'item_no' => 100),
);
$temp = array(); // create a temp array to hold just the item_no
foreach($my_array as $key => $val) {
$temp[] = $val['item_no'];
}
// now delete those entries which are not in temp array.
foreach($thrid_party_array as $key => $val) {
if(!in_array($val['item_no'],$temp)) {
unset($thrid_party_array[$key]);
}
}
Working link
If your key is not actually a key of your array but a value, you will probably need to do a linear search:
foreach ($itemsToRemove as $itemToRemove) {
foreach ($availableItems as $key => $availableItem) {
if ($itemToRemove['item_no'] === $availableItem['item_no']) {
unset($availableItems[$key]);
}
}
}
It would certainly be easier if item_no is also the key of the array items like:
$availableItems = array(
123 => array(
'item_no' => 123,
'item_name' => 'foo'
),
456 => array(
'item_no' => 456,
'item_name' => 'bar'
)
);
With this you could use a single foreach and delete the items by their keys:
foreach ($itemsToRemove as $itemToRemove) {
unset($availableItems[$itemToRemove['item_no']]);
}
You could use the following to build an mapping of item_no to your actual array keys:
$map = array();
foreach ($availableItems as $key => $availableItem) {
$map[$availableItems['item_no']] = $key;
}
Then you can use the following to use the mapping to delete the corresponding array item:
foreach ($itemsToRemove as $itemToRemove) {
unset($availableItems[$map[$itemToRemove['item_no']]]);
}