Find array key in objects array given an attribute value - php

I have an objects array like this:
Array
(
[945] => member Object
(
[id] => 13317
[name] => Test 999
[last_name] => Test 999
)
[54] => member Object
(
[id] => 13316
[name] => Manuel
[last_name] => Maria parra
)
[654] => member Object
(
[id] => 13315
[name] => Byron
[last_name] => Castillo
)
[656] => member Object
(
[id] => 13314
[name] => Cesar
[last_name] => Vasquez
)
)
I need to remove one of these objects according to an attribute value.
For example, I want to remove from the array the object id 13316.

Here is the functional approach:
$neededObjects = array_filter(
$objects,
function ($e) use ($idToFilter) {
return $e->id != $idToFilter;
}
);

function filter_by_key($array, $member, $value) {
$filtered = array();
foreach($array as $k => $v) {
if($v->$member != $value)
$filtered[$k] = $v;
}
return $filtered;
}
$array = ...
$array = filter_by_key($array, 'id', 13316);

Use array search function :
//return array index of searched item
$key = array_search($search_value, array_column($list, 'column_name'));
$list[key]; //return array item

Since there is already plenty solutions given, I suggest an alternative to using the array:
$storage = new SplObjectStorage; // create an Object Collection
$storage->attach($memberObject); // add an object to it
$storage->detach($memberObject); // remove that object
You could make this into a custom MemberCollection class with Finder methods and other utility operations, e.g.
class MemberCollection implements IteratorAggregate
{
protected $_storage;
public function __construct()
{
$this->_storage = new SplObjectStorage;
}
public function getIterator()
{
return $this->_storage;
}
public function addMember(IMember $member)
{
$this->_storage->attach($member);
}
public function removeMember(IMember $member)
{
$this->_storage->detach($member);
}
public function removeBy($property, $value)
{
foreach ($this->_storage as $member) {
if($member->$property === $value) {
$this->_storage->detach($member);
}
}
}
}
Might be overkill for your scenario though.

foreach ($array as $key=>$value)
if ($value->id==13316) {
unset($array[$key]);
break;
}

Related

Appending property to stdClass Object in PHP while in loop

Looping through an Array of stdClass Objects, I'd like to add a new property to the Object.
Of all the ways I've tried and researched, none end up adding the new property.
Array
(
[0] => stdClass Object
(
[id] => 12345678
[profile] => stdClass Object
(
[type] => superAdmin
)
)
[1] => stdClass Object
(
[id] => 89101112
[profile] => stdClass Object
(
[type] => admin
)
)
)
I have a function that takes in the above array, and then should iterate through it, if certain criteria met, add a new property to the object, and return the array.
public function addToProfile($usernameArr) {
$users = $usernameArr;
foreach ($users as $key => $user) {
if (in_array("admin", $user->profile->type)) {
$users[$key]->profile->newProperty = "newItem";
}
}
return $users;
}
I've also tried the json_decode(json_encode($users), true) way which did not end up with the result I'm looking for.
You can do it via transformation $user object to the array and back to object:
foreach ($users as $key=>&$user) {
if (in_array("admin", $user->profile->type)) {
// represents current $user->profile object as an array
$tmp = json_decode(json_encode($user->profile),true);
// add a new index
$tmp['newproperty'] = "$key newItem";
// transform back to an object
$user->profile = (object)($tmp);
}
}
Demo
You can put it into the function like:
function addNewProp($data, $prop_name, $prop_val){
foreach ($data as $key=>$user) {
if (in_array("admin", $user->profile->type)) {
$tmp = json_decode(json_encode($user->profile),true);
$tmp[$prop_name] = $prop_val;
$user->profile = (object)($tmp);
}
}
return $data;
}
Demo
Your input value of type has string datatype. Instead of
if (in_array("admin", $user->profile->type)) {
you should use
if ($user->profile->type === "admin") {
Generally, I try and avoid doing things like (object)array(...) and json_decode(json_encode()) in PHP as it is not immediately clear to the reader why your doing this round about stuff, so I will provide an alternative answer.
function addNewProp(array $users, $propName, $propVal)
{
for ($i = 0; $i < count($users); $i++) {
// You may need to do extra checking here if profile and type are not required.
if (isset($users[$i]->profile->type->admin)) {
$users[$i]->profile->$propName = $propVal;
}
}
return $users;
}

How to retrieve element in array by comparing its member value [duplicate]

I have an objects array like this:
Array
(
[945] => member Object
(
[id] => 13317
[name] => Test 999
[last_name] => Test 999
)
[54] => member Object
(
[id] => 13316
[name] => Manuel
[last_name] => Maria parra
)
[654] => member Object
(
[id] => 13315
[name] => Byron
[last_name] => Castillo
)
[656] => member Object
(
[id] => 13314
[name] => Cesar
[last_name] => Vasquez
)
)
I need to remove one of these objects according to an attribute value.
For example, I want to remove from the array the object id 13316.
Here is the functional approach:
$neededObjects = array_filter(
$objects,
function ($e) use ($idToFilter) {
return $e->id != $idToFilter;
}
);
function filter_by_key($array, $member, $value) {
$filtered = array();
foreach($array as $k => $v) {
if($v->$member != $value)
$filtered[$k] = $v;
}
return $filtered;
}
$array = ...
$array = filter_by_key($array, 'id', 13316);
Use array search function :
//return array index of searched item
$key = array_search($search_value, array_column($list, 'column_name'));
$list[key]; //return array item
Since there is already plenty solutions given, I suggest an alternative to using the array:
$storage = new SplObjectStorage; // create an Object Collection
$storage->attach($memberObject); // add an object to it
$storage->detach($memberObject); // remove that object
You could make this into a custom MemberCollection class with Finder methods and other utility operations, e.g.
class MemberCollection implements IteratorAggregate
{
protected $_storage;
public function __construct()
{
$this->_storage = new SplObjectStorage;
}
public function getIterator()
{
return $this->_storage;
}
public function addMember(IMember $member)
{
$this->_storage->attach($member);
}
public function removeMember(IMember $member)
{
$this->_storage->detach($member);
}
public function removeBy($property, $value)
{
foreach ($this->_storage as $member) {
if($member->$property === $value) {
$this->_storage->detach($member);
}
}
}
}
Might be overkill for your scenario though.
foreach ($array as $key=>$value)
if ($value->id==13316) {
unset($array[$key]);
break;
}

php searching in multidimensional array of unknown depth

I try to select the data of an array that was constructed by json_decode().
In principle it is an multiarray of unknown dimension.
First of all, I want to search recursively for a value in this array. As a next step I want to get some other values of the upper dimension. So here is an example:
I search for: "2345"
....
$json[3][6]['journal']['headline']="news"
$json[3][6]['journal']['article']=2345
....
$json[8]['journal']['headline']="weather"
$json[8]['journal']['article']=2345
....
After that I want to get the value of the element headline (returning "news" and "weather")
It might be that the element 2345 can be found in different dimensions!!!
Someone could probably do this with a RecursiveIteratorIterator object, but I personally have a hard time with iterator objects, so here is a fairly robust system:
<?php
// This will traverse an array and find the
// value while storing the base key
class RecurseLocator
{
public static $saved = array();
public static $find;
public static $trigger;
public static function Initialize($find = false)
{
self::$find = $find;
}
public static function Recursive(array $array)
{
foreach($array as $key => $value) {
if(!isset(self::$trigger) || (isset(self::$trigger) && empty(self::$trigger))) {
if(is_numeric($key))
self::$trigger = $key;
}
if(!is_array($value)) {
if($value == self::$find) {
self::$saved[self::$trigger] = $value;
}
}
if(is_array($value)) {
$value = self::Recursive($value);
if(!is_numeric($key))
self::$trigger = "";
}
$return[$key] = $value;
}
return $return;
}
}
// This class will traverse an array searching
// for a specific key or keys
class RecurseSearch
{
public $data;
public $compare;
public function Find($array = '',$find,$recursive = true)
{
$find = (is_array($find))? implode("|",$find):$find;
if(is_array($array)) {
foreach($array as $key => $value) {
if(preg_match("/$find/",$key))
$this->compare[$key] = $value;
if($recursive == true) {
if(!is_array($value)) {
if(preg_match("/$find/",$key)) {
$this->data[$key][] = $value;
}
$array[$key] = $value;
}
else {
if(preg_match("/$find/",$key))
$this->data[$key][] = $this->Find($value,$find);
$array[$key] = $this->Find($value,$find);
}
}
else {
if(preg_match("/$find/",$key))
$this->data[$key] = $value;
}
}
$this->data = (isset($this->data))? $this->data:false;
return $this;
}
}
}
// This function just wraps the RecurseSearch class
function get_key_value($array = array(), $find = array(),$recursive = true)
{
$finder = new RecurseSearch();
return $finder->Find($array,$find,$recursive);
}
USAGE:
$json[3][6]['journal']['headline'] = "news";
$json[3][6]['journal']['article'] = 2345;
$json[8]['journal']['headline'] = "weather";
$json[8]['journal']['article'] = 2345;
$json[4][1]['journal']['headline'] = "news";
$json[4][1]['journal']['article'] = 22245;
$json[5]['journal']['headline'] = "weather";
$json[5]['journal']['article'] = 233345;
// Set the search criteria
RecurseLocator::Initialize(2345);
// Traverse the array looking for value
$arr = RecurseLocator::Recursive($json);
// If found, will be stored here
$iso = RecurseLocator::$saved;
/* $iso looks like:
Array
(
[3] => 2345
[8] => 2345
)
*/
// Loop through the $iso array
foreach($iso as $key => $value) {
// Save to new array your search results
$new[] = get_key_value($json[$key],array("headline","article"),true);
}
/* $new looks like:
Array
(
[0] => RecurseSearch Object
(
[data] => Array
(
[headline] => Array
(
[0] => news
)
[article] => Array
(
[0] => 2345
)
)
[compare] => Array
(
[headline] => news
[article] => 2345
)
)
[1] => RecurseSearch Object
(
[data] => Array
(
[headline] => Array
(
[0] => weather
)
[article] => Array
(
[0] => 2345
)
)
[compare] => Array
(
[headline] => weather
[article] => 2345
)
)
)
*/
?>
Just as a side note, the above class stores multiple found in the [data], and then stores them also in the [compare], however the [compare] will overwrite itself if multiple same-keys are found in one array where as [data] will just keep adding values.
just create a function for compile unknown array. try this
$json[1][6]['journal']['headline']="news";
$json[1][6]['journal']['article']=2345;
$json[3][6]['journal']['headline']="HOT";
$json[3][6]['journal']['article']=2345;
$json[8]['journal']['headline']="weather";
$json[8]['journal']['article']=2345;
$json[10]['journal']['headline']="weather";
$json[10]['journal']['article']=2345;
$GLOBALS['list_scan'] = array();
$result = array();
foreach ($json as $key => $value)
{
if (is_array($value)) {
_compile_scan($key, $value);
}
}
echo "<pre>";
print_r($GLOBALS['list_scan']);
echo "</pre>";
$search = "2345";
$keyword = "article";
$keyFinder = "headline";
foreach ($GLOBALS['list_scan'] as $key => $value)
{
if ($value == $search)
{
$addr = substr($key, 0, -(strlen($keyword))).$keyFinder;
if (!empty($GLOBALS['list_scan'][$addr]))
{
$result[] = $GLOBALS['list_scan'][$addr];
}
}
}
echo "<pre>";
print_r($result);
echo "</pre>";
function _compile_scan($index, $value)
{
$pointer =& $GLOBALS['list_scan'];
foreach ($value as $key => $val)
{
$temp = '';
$temp = $index.'|'.$key;
if (is_array($val))
{
// $pointer[$temp] = $val;
_compile_scan($temp, $val);
}
else $pointer[$temp] = $val;
}
}
output:
Array
(
[1|6|journal|headline] => news
[1|6|journal|article] => 2345
[3|6|journal|headline] => HOT
[3|6|journal|article] => 2345
[8|journal|headline] => weather
[8|journal|article] => 2345
[9|journal|headline] => Others
[9|journal|article] => 234521
)
Array
(
[0] => news
[1] => HOT
[2] => weather
)

Searching a multidimensional array for objects

I have a multidimensional array in PHP and want to be able to search through it and find all values that are objects.
The reason I want to do this is so that when an object is found I can replace it with an array by calling an output() method on it. The output() method uses get_object_vars() to turn itself into an array, which it then returns.
Here's an example which achieves what I want manually (but only with 2 levels of depth):
// First level search...
foreach($array as $k => $v) {
// Check if it's an array.
if (is_array($v)) {
// Second level search...
foreach($v as $k2 => $v2) {
// If it's an object - convert it!
if (is_object($v2)) {
$array[$k][$k2] = $array[$k][$k2]->output();
}
}
}
// If it's an object - convert it!
if (is_object($v)) {
$array[$k] = $array[$k]->output();
}
}
Tim Cooper's answer is wrong because the function must have a parameter that is passed by reference and not by value.
php > class Foo { public function output() { return "this was an object"; } }
php > $a = array( 1 => array( 2 => array( 'foo', 'red', 1, new Foo() ) ) );
php > array_walk_recursive( $a, function( $item, $key ) {
if ( is_object( $item ) ) {
$item = $item->output();
}
} );
php > print_r( $a );
Array
(
[1] => Array
(
[2] => Array
(
[0] => foo
[1] => red
[2] => 1
[3] => Foo Object
(
)
)
)
)
Versus passing by reference:
php > array_walk_recursive( $a, function( &$item, $key ) {
if ( is_object( $item ) ) {
$item = $item->output();
}
} );
php > print_r( $a );
Array
(
[1] => Array
(
[2] => Array
(
[0] => foo
[1] => red
[2] => 1
[3] => this was an object
)
)
)
You just need a recursive function:
function objects_to_arrays_recursive (&$array) {
foreach ($array as &$member) {
if (is_object($member)) {
$member = $member->output();
}
if (is_array($member)) {
objects_to_arrays_recursive($member);
}
}
}
This will call the output() method of every object and store the result in the key that originally held the object.
Caveats:
This will loop the objects once they have been converted and also convert child objects. You may not want to do this, particularly if you have circular references as this would result in an infinte loop. It can be avoided just by changing the 2 ifs into if / elseif.
This does not check whether a given object has an output() method to call. You should probably add an is_a()/instanceof check.
This function takes its argument by reference, which means the input array will be modified. If you need to keep the original array intact, you will need to make a copy of it first.

Search array path with related values

I'm working on a menu system and am working on some complex issues. The menu is generated from a array. This array is included in a pastebin because it's really big. I want to search in the array and get the hierarchical path of the value I'm searching while also getting the values next to the parents you run trough. As I said its quite complex.
In the pastebin is the array and the result I want to function to return:
-->pastebin<--
I tried writing this function quite a few times but always get stuck in the middle.
Here is a function:
function get_item_recursive($id, $menu_array = array())
{
foreach($menu_array as $menu_item)
{
if(isset($menu_item['id']) && $menu_item['id'] == $id)
{
$menu_item['subitems'] = array();
return $menu_item;
}
else
{
if(isset($menu_item['subitems']) && !empty($menu_item['subitems']))
{
$found = get_item_recursive($id, $menu_item['subitems']);
if($found)
{
return $menu_item;
}
}
}
}
return FALSE;
}
I have not tested it, but this is the idea.
You are basically looking for the path to build something like a breadcrumb? You can use a recursive function for that:
function findPath($haystack, $id, $parents = array()) {
foreach ($haystack as $k => $v) {
if ($v['id'] == $id) {
return array_merge($parents, array($v));
} else if (!empty($v['subitems'])) {
unset($v['subitems']);
$return = findPath(
$haystack[$k]['subitems'],
$id,
array_merge($parents, array($v))
);
if ($return) return $return;
}
}
return false;
}
Executing this function like this:
findPath($haystack, 11);
Would return:
Array (
[in-balans] => Array
(
[id] => 2
[slug] => in-balans
[title] => In balans
)
[arbodienstverlening] => Array
(
[id] => 10
[slug] => arbodienstverlening
[title] => Arbodienstverlening
)
[arbo] => Array
(
[id] => 11
[slug] => arbo
[title] => Arbo
[subitems] =>
)
)

Categories