php Remap array keys for multi-dimensional array - php

I have a JSON object I've turned into an array, this needs to be stored into my database, the trouble is my table has field called id, however in the array it's called group_id.
What's the most efficient way of traversing my multi-dimensional array converting all the group_id keys to id so I can pass it to my SQL storage function? I want to function to work with an array or an array or arrays.
I had planned to make a function:
$db->remap($array, [ 'group_id' => 'id' ]; then I can pass a list of all the fields I want remapping.
array_walk_recursive doesn't help because it won't let you modify the keys, I looked at a recursive function call, but struggled to keep track of the array.

I managed to get it working, including here to help others, if there is a better way please let me know, thanks.
/**
* Recursively remap array keys
* #param array $array Array to search
* #param array $mapping Key value pairs of the keys to map [ 'fromKey' => 'toKey' ]
* #return array Returned remapped array
*/
public function remapArray(array $array, array $mapping) {
$newArray = [];
foreach ($array as $key => $value) {
if (is_array($value)) {
// This is also an array, resursively call
$newArray[$key] = $this->remapArray($value, $mapping);
} else {
if (! empty($mapping[$key])) {
// Match, replace key
$newArray[$mapping[$key]] = $value;
} elseif (! in_array($key, $mapping)) {
// Only store if this key doesn't match the target
$newArray[$key] = $value;
}
}
}
return $newArray;
}

Related

fill mapped array in php controller

I am passing an array from controller to view in PHP CodeIgniter.
Here is my code in controller.
$gen is any array containing many values.
foreach ($gen as $value) {
$moviesbyid['similarmovie'] = $this->main_model->getsimilarmovies($value);
}
$this->load->view('home/check.php', $moviesbyid);
But the above code fill $moviesbyid['similarmovie'] array only for one value of $value.
I want that it contain all the values returned from getsimilarmovies($value) for every value of $value.
How can i do this?
Here is the method in model:
public function getsimilarmovies($gener)
{
$this->db->limit(4);
$this->db->like('Genre',$gener);
$query = $this->db->get('sources');
return $query->result();
}
You need to create new items in the array as it loops.
Your code just overwrite the same item every iteration.
foreach ($gen as $value) {
$moviesbyid['similarmovie'][]=$this->main_model-
>getsimilarmovies($value);
}
notice the []

Can I use a function in PHP's array_search or sort function?

I am using Parse.com APIs, though I wouldnt say this is a Parse question.
I have an array of ParseObjects called $groups and an array of ParseObjects called $inputs.
I already have both of these, so I do not want make any new queries.
All of the input objects are children of one of the group objects. I'd like to get an array of all of the $inputs that belong to each $group.
One way I could do this would be:
$groups= // array of ParseObjects
$inputs= // array of ParseObjects
foreach ($groups as $group)
{
$inputsInGroup=array();
foreach ($inputs as $input)
{
if($input->get('parent')==$group)
{
array_push($inputsInGroup,$input);
}
}
//here I can use $inputsInGroup which will contain all elements that have this group as their parent
}
That would work, but seams really inefficient as it has to search the whole list of inputs for each group, including any that it already determined belonged to a previous group.
Is there a way to supply a function to array_search () or sort() to return objects in the array that pass this check $input->get('parent')==$group?
I know you can do this with jQuery's sort() seems like PHP likely has a similar method.
You had an unneeded nested loop there - that's why
$groups; // array of ParseObjects
$inputs; // array of ParseObjects
$ibg; // inputs by group
foreach($inputs as $input) {
var $group = $input->get('parent')->getObjectId();
if(!isset($ibg[$group])){
$ibg[$group] = array();
}
$ibg[$group][] = $input;
}
What you're asking for is to apply a filter, with a custom callback, to an array, which can be done with array_filter. However, the change is only paradigmatic in nature — in that the asymptotic complexity won't change much.
array_filter($groups, function ($group) use ($inputs) {
foreach($inputs as $input) {
if ($input->get('parent') == $group) {
return true;
}
}
});
Both are still O(n * k) in time complexity, but one uses a more functional, as opposed to procedural, approach.

Recursive function to sort an array of objects

I've been trying to write a recursive function that would reorder an array of objects based on the order provided by another array (simple, numeric array).
I want to use this sorting function to sort an array of objects by a 'template' array that would hold only one property of each object present in the array to sort, e.g.
$template = ['A', 'B', 'C']
Array to sort:
$myArray = [
new Element('B'),
new Element('C'),
new Element('A'),
]
class Element
{
public $name;
public function __construct($name)
{
$this->name = $name;
}
}
I was not successful. Perhaps you might have an idea about how to apprach this task?
I don't see how recursion would help you with that task. This is how you can use the built in sort functions:
usort($myArray, function(Element $a, Element $b) use ($template) {
return array_search($a->name, $template) - array_search($b->name, $template);
});
usort sorts by given comparison callback
I added the Element type hint to the callback because the sort function will only work with arrays of Element objects
array_search returns the key for the given name property value within the $template array. If the value does not exist in the array, it will be placed at the beginning, because the result false is coerced to 0.
I also managed to do the sorting using recursion - here it is:
function orderRecursively($template, $myArray, &$ordered)
{
foreach($myArray as $k => $v) {
if ($myArray[$k]->name == $template[0]) {
$ordered[] = $myArray[$k];
array_splice($template, 0, 1);
}
}
if (!empty($template)) orderRecursively($template, $myArray, $ordered);
}
$ordered = [];
order($template, $myArray, $ordered);
$ordered would then hold the sorted array of objects.
Still, I find #fschmengler's answer more elegant.

Return multidimensional array value based on other array element

Given the following array and a given id, how can I return the corresponding elem? For instance, given id=6, it should return goodby. The id values are the PKs from a database, thus will always be unique.
Obviously, I could just iterate over the first array, check the values, and break and return the elem upon match, but I expect there is a much more elegant way to do this.
array(
array('id'=>2,'elem'=>"hello"),
array('id'=>6,'elem'=>"goodby"),
array('id'=>8,'elem'=>"goodnight")
);
A basic alternative to consider would be to collect the columns with array_column (indexed by the id column) and then dereferencing the array to access the passed index value $id, something like:
$myArray = array(
array('id'=>2,'elem'=>"hello"),
array('id'=>6,'elem'=>"goodby"),
array('id'=>8,'elem'=>"goodnight")
);
function getValue($id, $a)
{
return array_column($a, 'elem', 'id')[$id];
}
var_dump(getValue(6, $myArray));
Enhancing the proof to get more control:
function getValueAlternative($where, $get, $fromSource)
{
$where = explode("=", $where);
return array_column($fromSource, $get, $where[0])[$where[1]];
}
var_dump(getValueAlternative("id=2", "elem", $myArray));
var_dump(getValueAlternative("elem=hello", "id", $myArray));
See this :
myfunction($products, $needle)
{
foreach($products as $key => $product)
{
if ( $product['id'] === $needle )
return $key;
}
return false;
}
Similar : PHP Multidimensional Array Searching (Find key by specific value)
Why don't you use the following structure?:
array(
2 => array('elem'=>"hello", ...),
6 => array('elem'=>"goodby", ...),
8 => array('elem'=>"goodnight", ...)
);
Then you could access them like:
$array[$id];
You told that you've used PDOStatement::fetchAll() to obtain your array. You can tell fetchAll() to return a structure like I've suggested, you need to use the fetch mode PDO::FETCH_GROUP:
$pdo->query('SELECT * FROM table')->fetchAll(PDO::FETCH_GROUP);
Well defined data structures are the essential basics of a good program. In your case an associative array having the ids as their keys and the whole records as the value portion,will be better than a numeric array as it allows you to perform fast, id based access. Of course you have to pay for this - with a little more memory.
You could use the array_search PHP function:
/**
* #param array $array
* #param int $id
* #return string|null
*/
function getElem(array $array, $id) {
foreach($array as $subArr) {
if(($key = array_search($id, $subArr, true)) !== false) {
if(strcmp($key, "id") === 0) {
return $subArr['elem'];
}
}
}
return null;
}
$array = array(
array('id'=>2,'elem'=>"hello"),
array('id'=>6,'elem'=>"goodby"),
array('id'=>8,'elem'=>"goodnight")
);
echo getElem($array, 6);

PHP array_diff with instances or custom callback function?

I have many arrays, each holding instances of Product. Need to get unique products only. From PHP documentation of array_diff:
array array_diff ( array $array1 , array $array2 [, array $... ] )
Two elements are considered equal if and only if (string) $elem1 ===
(string) $elem2. In words: when the string representation is the same.
Does this mean I'm forced to implement toString() in my instances? Is there any function to compute the difference providing a custom callback?
I didn't tested this code, but I guess it will not work because there is no toString() function in Product:
$categories = array();
// ...
// Unique products from all categories, compared against ===
$uniqueProducts = array();
// Compute unique products
foreach($categories as $category) {
$uniqueProducts += array_diff($category->getProducts(), $uniqueProducts)
}
return $uniqueProducts;
Does this mean I'm forced to implement toString() in my instances?
According to the typecast section in the PHP docs manual - you do not need a toString() function. Basically typecasting (string) is the same as if you simply did var_dump($uniqueProducts)
All that the array_diff is doing is typecasting your array.
One option is to make your own "array_diff" function
function my_array_diff($arraya, $arrayb)
{
foreach ($arraya as $keya => $valuea)
{
// Put your own 'test' here - but for example this uses in_array()
if (in_array($valuea, $arrayb))
{
unset($arraya[$keya]);
}
}
return $arraya;
}
If the product lists are short you could implement your own checking, based on values of your choice?
$uniqueProducts = array();
foreach($productsOne as $productOne) {
foreach($uniqueProducts as $alreadyListed) {
if($productOne->getName() != $alreadyListes->getName()) { // You can customise this line to make more specific
break;
}
$uniqueProducts = $productOne; // If product hasn't already been added to the array then it's unique.
}
}
// Repeat foreaches for second product array, or combine them before teh foreach using $productOne = $productOne+$productTwo.

Categories