PHP Arrays, ordered or not? - php

I have an Array of product types in PHP, it looks pretty much like this:
$types = [
0 => "cars",
1 => "motorbikes",
2 => "boats",
3 => "airplanes"
];
So that when then user wants to get or save it, I can use the ID of the category to insert or get it from the database, like this:
select * from items where type = 0;
now, My doubt is the following: if I am using integer index keys, would it not be the same to use the following?
$types = ["cars", "motorbikes", "etc."];
Since PHP will give an integer auto-ordering.
Which one would you consider to be best practice in this case? The advantage of the first example seems to only be the fact that I can assign different keys, like for private categories or such, but I don't know really.
It is also important to consider that the values will need to be translated so, should I consider even just using IDs? like
$types = ["t1", "t2", "etc."];
and then insert the translation somewhere else?

There are 2 possible options.
Your current option 1 with manually set indexes.
A way better one - a table in the DB, holding these categories, which allow editing categories without losing the association between keys and names.
Your current option 2 is not an option at all - it will break the order the same moment you insert or delete a category
Here you set the index:
$types = [
3 => "airplanes"
index ^ ^ value
So, if you delete cars from the list, the index remain associated with it's value:
$types = [
1 => "motorbikes",
2 => "boats",
3 => "airplanes"
];
While if you don't set indexes manually
$types = ["motorbikes", "boats", "airplanes"];
airplanes will lose it's association, and become boats. It's not ht magic we expect from the web application

It all depends on the project. If I'm working with an array of items from the database I like the key to be the id from the database so it's available should I need it. If there's no need for the ids then there is no need to define a key. It will start at 0 anyways.

I think your first approach is a good one. You could even do it as default translation:
$types["en"] = []
Of course if you have a default language variable, you can use it from the start, and it will be much easier in the future to translate it further and expand
The arrays will be seen as the same so you can order it and take key as ID but it's not the best practice, all depends on how you design your relationship between arrays, php and database.

I might be missing your question but the array in PHP is ordered hash map basically. So ["cars", "motorcycles", "etc."] is guaranteed to preserver ordering (and have keys 0, 1, 2). But you might instead consider do the following
class AutoTypes {
const TYPE_CAR = 0;
const TYPE_MOTORCYCLE = 1;
const TYPE_BOAT = 2;
public static function getLabels() {
return array(self::TYPE_CAR => 'Car', self::TYPE_MOTORCYCLE => 'Motorcycle', self::TYPE_BOAT => 'Boat');
}
}
This way you can refer to the auto type by AutoTypes::CONSTANT. Because if you want to remove motorcycle at some point, not using clear indexes in the array, removing an item will brake your logic.

In my opinion, in this circumstance it's better to use
$types = ["cars", "motorbikes", "etc."];
As you say, PHP automatically assigns integer indexes starting from 0; so there's no need to specify the index that it would be assigned anyway.
It's up to you however, if you feel that it isn't clear enough just to declare an array without specifying the indexes manually then that's up to you. But personally I feel that it's obvious to any competent programmer and so therefore it's a waste of time and hard disk space to manually specify those indexes.

Related

Making fictional "people" using random, getting lots of clones (PHP, Mysql)

So, I'm trying to make a gladiator game, where the players will be lanistas. I'm going for realism, so the gladiators will die in the arena, making a big influx of new "recruits" necessary.
For now, each newly created gladiator has 21 attributes, ranging from numerical values for things such as strength and agility, to text for faction and name. These are calculated by random functions. Names and factions I'm picking randomely from arrays with (at least for names) a relatively big list of realistic names. Numerical values are simply rand(x,y).
Before I added the name and faction arrays, I tried several times running the file that create gladiators with a while loop creating 10000 gladiators, without any clones emerging, as far as I could see. Now, with picking names too from random (as described above), everything works fine if I create a small number of gladiators, but once I use a number of a couple of hundred for my while loop, or if I run the file a few times in a row with as low a number as 50 in my while loop, I get clones.
With 21 attributes, 100 different values+ for most of them, getting clones doesn't happen by chance. Can anyone tell me what's wrong? This can kill my game, and I was just getting optimistic after overcoming a few (easy) challenges.
Oh, and yeah, the gladiators with the attributes are put into a mysql database automatically.
Edit (update):
I went back in my stuff, removed the naming and faction random functions, and set all to "s". Created 10000 gladiators named s s from faction s, and it seems there are excactly 0 clones - nobody with the exact same stats.
Reactivated the random name functions. Ran the file, creating 200 gladiators. Couldn't see clones. Ran it again. One clone for each gladiator. And again. Now two clones for the gladiators.
This random function isn't random at all, is it?
Edit (update 2):
Tested it again, with one of the previously excluded random functions activated one at a time. It seems its the firstname and surname functions that are screwing things up. Also, from my last test, it seems like there's a pattern, with gladiator id 209 being equal to 737, 77 being equal to 605 and 1133, 148 equal to 676, 772 equal to 244, and so on.
737-209, 605-77, 1133-605, 676-148, 772-244 all have one thing in comon. They all equal 528.
This isn't much random at all.
The function I use for getting names goes something like:
$surname=surname($faction) //surname is a function, using the variable $faction
function surname($faction) {
if ($faction=="Roman") {
$nomen = array("Aburius", "Accius", [...]);
$cognomen = array("Zeno", "Zonsimus", [...]);
$randnomen=array_rand($nomen,1);
$randcognomen=array_rand($cognomen,1);
$merge=array($nomen[$randnomen],$cognomen[$randcognomen]);
$surname=implode(" ",$merge);
return $surname;
}
To clarify: The [...] in the $nomen and $cognomen arrays is there in place of hundreds of roman names, to save space and your time.
array_rand seems to have a problem with randomness see here.
I prefer to use mt_rand myself.
The following function can create random names with either1,2 or three parts.
function randomName(){
$numargs = func_num_args();
$first = func_get_arg(0);
$one = count($first)-1;
$name = $first[mt_rand( 0,$one)]; //count($array)-1
if($numargs > 1){
$middle = func_get_arg(1);
$two = count($middle)-1;
$name .=" ". $middle[mt_rand( 0,$two)];
}
if($numargs > 2){
$last = func_get_arg(2);
$three = count($last)-1;
$name .= " ".$last[mt_rand( 0,$three)];
}
return $name;
}
USE
$var= randomName($first,$middle,$last);// 3 names
$var= randomName($first,$last);// 2 names
etc
WHERE $first,$middle,$last are arrays
With only ~100 values for an attribute and 1000s of gladiators, there may be many with the same name attribute, for example.
If you mean that there may be multiple gladiators where all 21 attributes are the same, then the only way to guard against that is to check newly created gladiators against the existing ones and if there is a match regenerate the new one.
Just like you would when someone registers for a site, normally username and email address must be unique per user, so you have to check first.
The easiest and most performant in this case might be to generate a "hash" of each gladiator's properties and check if it exists before generating a new gladiator. This will make them all unique, so you also need to consider how unique do you want them? Can 2 or more gladiators have 20 properties in common? How about 15, etc?

Assign array value to a field

I am working with migration and I am migrating taxonomy terms that the document has been tagged with. The terms are in the document are separated by commas. so far I have managed to separate each term and place it into an array like so:
public function prepareRow($row) {
$terms = explode(",", $row->np_tax_terms);
foreach ($terms as $key => $value) {
$terms[$key] = trim($value);
}
var_dump($terms);
exit;
}
This gives me the following result when I dump it in the terminal:
array(2) {
[0]=>
string(7) "Smoking"
[1]=>
string(23) "Not Smoking"
}
Now I have two fields field_one and field_two and I want to place the value 0 of the array into field_one and value 1 into field_two
e.g
field_one=[0]$terms;
I know this isn't correct and I'm not sure how to do this part. Any suggestions on how to do this please?
If you are only looking to store the string value of the taxonomy term into a different field of a node, then the following code should do the trick:
$node->field_one['und'][0]['value'] = $terms[0];
$node->field_two['und'][0]['value'] = $terms[1];
node_save($node);
Note you will need to load the node first, if you need help with that, comment here and will update my answer.
You are asking specifically about ArrayList and HashMap, but I think to fully understand what is going on you have to understand the Collections framework. So an ArrayList implements the List interface and a HashMap implements the Map interface.
List:
An ordered collection (also known as a sequence). The user of this interface has precise control over where in the list each element is inserted. The user can access elements by their integer index (position in the list), and search for elements in the list.
Map:
An object that maps keys to values. A map cannot contain duplicate keys; each key can map to at most one value.
So as other answers have discussed, the list interface (ArrayList) is an ordered collection of objects that you access using an index, much like an array (well in the case of ArrayList, as the name suggests, it is just an array in the background, but a lot of the details of dealing with the array are handled for you). You would use an ArrayList when you want to keep things in sorted order (the order they are added, or indeed the position within the list that you specify when you add the object).
A Map on the other hand takes one object and uses that as a key (index) to another object (the value). So lets say you have objects which have unique IDs, and you know you are going to want to access these objects by ID at some point, the Map will make this very easy on you (and quicker/more efficient). The HashMap implementation uses the hash value of the key object to locate where it is stored, so there is no guarentee of the order of the values anymore.
You might like to try:
list($field_one, $field_two) = prepareRow($row);
The list function maps entries in an array (in order) to the variables passed by reference.
This is a little fragile, but should work so long as you know you'll have at least two items in your prepareRow result.

Fastest way to do name value pair look up for a long list

I'm working with a long list of name - value pairs and I will be checking with this list alot so I wanted to know what you guys think is the fastest way to do named value pair look ups. An example of my problem is as follows:
Using PHP
The variables are on the left side with the string value they are suppose to represent. There are roughly 68 variable with corresponding string values.
rKid = Hiking
rSpo = Sports
rFly = Flying
I will need a look up every web page to see what each of the variables could correspond to.
I was thinking of an array -> list value look up, but unsure of how to implement that.
Associative arrays in PHP are in fact hash maps, so lookup by key is very efficient. What you need is this structure:
$map = array(
'rKid' => 'Hiking',
'rSpo' => 'Sports,'
'rFly' => 'Flying'
);
And the lookup is straightforward:
echo $map['rKid']; // 'Hiking'

Is it possible to define the key when inserting into mongodb

Background: Using CodeIgniter with this MongoDB library.
This is my first go-round with mongodb and I'm enjoying it thus far. It's taken a while for me to separate myself from the sql way of thinking, but it is a perfect fit for my current project.
I'm trying to push an array into a document using...
$this->mongo_db->where(array('_id'=>$estimate_id))->push("measurements", $newData)->update('estimates');
If I encode $newData using json_encode($newData) I get {"levels":[{"level_qty":12,"level_uom":"ft"}]}
The problem is, when my function creates the measurements line in the mongodb document, it automatically starts an array with my insertion at [0]. Like this...
"measurements" : [ { "levels" : [ { "level_qty" : 12, "level_uom" : "ft" } ] }]
...leaving me with...
-measurements
--0
----levels
-----0
------level_qty => 2,
------level_uom => ft
What I really want is...
-measurements
--levels
---0
----level_qty => 2,
----level_uom => ft
I'm certain I'm missing something fairly elementary (i.e. php related & not mongodb related), but I'm an admitted amateur who has waded too deep.
$push is used to append a value to an array. In your example, measurements is an array and Mongo is appending $newData as its first element. This explains the 0 index between measurements and levels. In your desired result, measurements is an object equivalent to $newData (i.e. it has a levels property, which in turn has an array of objects within).
Either of the following examples should accomplish what you want:
// if $newData is {"levels": [{"level_qty":12,"level_uom":"ft"}]}
->set("measurements", $newData)
// if $newData is [{"level_qty":12,"level_uom":"ft"}]
->set("measurements.levels", $newData)
// if $newData is {"level_qty":12,"level_uom":"ft"}
->push("measurements.levels", $newData)
Note: $push is going to be more flexible if you want to append data with future updates, whereas $set will naturally overwrite the given field.

Declaring static arrays in php

I am new to php. I was wondering how I could declare a static array in php. Here is what I would do in C. How is the corresponding php code for it?
char a[][] = { (1,1), (1,2), (1,3), (2,1), (2,2), (2,3), (3,1), (3,2), (3,3) };
From what I read it has to be something like this -
$a = array( 1 => array(1,1), 2 => array(1,2), ... );
Is this correct? If so it sucks :) I hope I am wrong.
Thanks,
- Pav
You've already found the way to do it natively.
Another option would be to declare your data as JSON (a very concise and human-friendly format). This could be either in a separate file bundled with your app, or directly in your code in a string. Then parse the JSON at runtime. Since PHP isn't exactly known for speed, this may or may not make your noticeably app slower to start.
you have it already figured out in your question.
One thing I would add is that you do not need to explicitly define the keys if you are intending to use a zero based array, this is assumed and can be done like so...
$a = array(array(1,1),array(1,2), ... );
You can also use what is called associative arrays which use string keys and you define them the same way you do in your example, except use strings instead of numbers...
$ass_array = array( 'array_1' => array(1,1), 'array_2' => array(1,2), ... );
you would then call your associative array like this...
$ass_array['array_1'];
Also, if you want to append single items to an array (for example in a loop to load an array)...
$ass_array[] = $item;
Further to jondavidjohn's anwser, you could just write a quick script to grab your list of values and generate the array statement for you.
No need to care how verbose the syntax is then. If the task is long and repetitious enough to care, don't do it by hand. :)

Categories