Reference an arrays key in its value - php

I know this seems like something that should be averted by design, but let's just say it is bitterly needed:
Is it possible to reference the key belonging to a value while it is being initialized?
Here is what I imagine it to be (not exactly the case in which I need it, but the key is primitive as well):
$array = array(25 => "My key is " . $this->key);
I need this because the array key is used in each value. Actually the value is another array which has a value in which the first array key is used. Like I said in the comments, I want to keep it DRY. Doing it is no problem, but I want to do it good ;)

If you are writing an array yourself you can just put key value to array value like:
$array = array(25 => "My key is 25");
If you are have an array already you can use a foreach and add all keys to it's values:
foreach($array as $key => $value) {
$array[$key] = sprintf('%s %s', $value, $key);
}
Or if you just want to have an array of keys of existing array you can use either array_flip if you want to maintain key=>value, but have keys and values flipped. Or you can use array_keys if you want just an array of keys.
To make what you want: initialize an array somewhere and do not add any keys to it's value you can implement ArrayAccess, Countable and have:
public function offsetGet($offset) {
return isset($this->container[$offset])
? $this->container[$offset] . ' ' . $offset
: null;
}
or something like this. But in this case you need to have a variable that contains this array to be an instance of your ArrayAccess implementation. And depending of usage of this class you probably will need to implement more interfaces.

No, there is no way to reference the key when defining the value. Except maybe writing a preprocessor that embeds it in the string. But that would only work for primitive values.

Related

Filtering collection of key/value pairs. How can I access the key?

I am filtering through a collection of key/value pairs. While I am filtering, how can I access the key?
Keys are:
title
body
active
button
button-2
How can I return fields whose key starts with "button"?
In this case, I would only like to get the button and button-2 field.
$fields = (stuff in picture)
// Pseudocode of what I'm trying to do
$button_fields = collect($fields)->filter(function($field){
// I imagine getting the key should be something like this?
if($field->key->beginsWith('button')) {
return;
}
});
On most collection methods the second parameter is the $key. This can be done, because you loop over an associative array, therefor the key is not indexed but a value. Secondly strings in PHP does not have methods, there for you should use the Str helper from Laravel, which takes two parameters the haystack first and the needle secondly.
$buttonFields = collect($fields)->filter(function($field, $key){
if(Str::startsWith($key, 'button')) {
return;
}
});

Sorting array of objects by object variable, key being replaced

I have got an array of object instances, I need to sort these based on what a function within the object returns.
So basically my object has got 2 variables, the function will add them together, and then return the result, the list of objects need to be sorted based on this.
My sorting code:
function cmp($a, $b)
{
if ($a->calcPoints() == $b->calcPoints()) {
return 0;
}
return ($a->calcPoints() > $b->calcPoints()) ? -1 : 1;
}
usort($teamData, "cmp");
Without using the usort function I get the following when dumping my array:
Key: "Hull City FC" Value:
{"win":3,"draw":2,"loss":8,"goalFor":11,"goalConc":28} Key: "Leicester
City FC" Value: {"win":3,"draw":4,"loss":6,"goalFor":16,"goalConc":22}
Once I used the usort function, my keys are being replaced like so:
Key: 0 Value: {"win":10,"draw":1,"loss":2,"goalFor":29,"goalConc":10}
Key: 1 Value: {"win":9,"draw":3,"loss":1,"goalFor":29,"goalConc":12}
How can I stop this?
If you lookup usort() in the manual, you'll find:
Note: This function assigns new keys to the elements in array. It will remove any existing keys that may have been assigned, rather than
just reordering the keys.
uasort(), however, will: "Sort an array with a user-defined comparison function and maintain index association". Go ahead and try that, it should be what you're looking for.
You should use uasort function instead of usort. According to PHP documentation:
uasort — Sort an array with a user-defined comparison function and
maintain index association

Laravel lists function prepend value

Laravel lists function used to return an array so I could prepend a value. However it now is an object. What I would like to do is generate a list for a dropdown but add an extra value to the front that says something like:
['select a value.', '0']
How should I prepend data to the new Laravel lists function?
lists() returns a Collection object. To add an item to the beginning of the collection, you can use the prepend method:
$statusCollection = \App\Status::lists('name', 'id');
$statusCollection->prepend('select a value', 0);
Make sure you pass in a non-null key as the second parameter to prepend, otherwise this method will end up renumbering your numeric keys. If you don't provide a key, or pass in null, the underlying logic will use array_shift, which will renumber the keys. If you do provide a key, it uses an array union (+), which should preserve the keys.
For another option, you can get the underlying item array using the all() method and just do what you did before:
$statusCollection = \App\Status::lists('name', 'id');
$statusArray = $statusCollection->all();
// if you want to renumber the keys, use array_shift
array_unshift($statusArray, 'select a value');
// if you want to preserve the keys, use an array union
$statusArray = [0 => 'select a value'] + $statusArray;
If you are ok with the numeric keys being reindexed, then the accepted answer of using array_unshift() works. If you want to maintain the original numeric keys (for example, if the keys correspond to the id of your table entries), then you could do as follows:
$statusCollection = \App\Status::lists('name', 'id');
$statusArray = $statusCollection->all();
$finalArray = array('0' => 'Select a value') + $statusArray;

Use object property as array key

I have a PHP array of objects, say with two properties a and b. So for example I can do
$arr['a1']->a = $z;
$x = $arr['a1']->b;
The array is currently using the value of each object's a property as the array key, e.g.
$arr['a1']->a == 'a1'
This is so I can quickly look up the object by that property. I now need to quickly look up by b, and so want to switch the keys from being set to property a to being set to b (both are unique).
Is there an easy way to do this? In-place or into another array are both fine.
foreach($arr as $key => $object)
{
$arr2[$object->b] = $object;
}
This will create a new array that points to the same objects.
If you want them in one array, you can do as Joost suggested in the comments ($arr[$object->b] = $object; in the loop instead). However, that will only work if there are no duplicate keys between the two sets.

Doctrine table IDs as array IDs

I found a very useful Doctrine function to set an attribute on a table for getting the database IDs also as keys in the resulting Doctrine_Collection. This function is documented here: http://www.doctrine-project.org/projects/orm/1.2/docs/manual/component-overview/en#collection:key-mapping
Now the question. I cannot use the table object itself, because I need to create a dynamic query on the table (and not the magic finders as in the example).
I tried this code:
$doctrineTable = Doctrine_Core::getTable($table);
$doctrineTable->setAttribute(Doctrine_Core::ATTR_COLL_KEY, "id");
$q = $doctrineTable->createQuery("t");
foreach ($filter as $c => $v) // lopp thru coumns
if (is_array($v)) // use whereIn if value is an array
$q->andWhereIn("t." . $c, $v);
elseif (is_null($v)) // use is null for null values
$q->andWhere("t." . $c . " IS NULL");
else // use where in other cases
$q->andWhere("t." . $c . "=?", $v);
return $q->fetchAll();
Unfortunately the resulting collection is still not using an associative array, but a normal one just using keys from 0 up.
Anybody has an idea how to achieve that for a query on a single table?
Cheers,
Daniel
You are looking for the INDEXBY keyword.
The INDEXBY keyword offers a way of mapping certain columns as collection / array keys. By default Doctrine indexes multiple elements to numerically indexed arrays / collections. The mapping starts from zero. In order to override this behavior you need to use INDEXBY keyword

Categories