I have a multi-dimensional array of databases, which was generated from my server:
// place db tables into array
$da_db = array(
'test' => array(
// test.users
'users' => array('fname','lname','info'),
// test.webref_rss_details
'webref_rss_details' => array('id','title','link','description','language','image_title','image_link','item_desc','image_width','image_height','image_url','man_Edit','webmaster','copyright','pubDate','lastBuild','category','generator','docs','cloud','ttl','rating','textInput','skipHours','skipDays'),
// test.webref_rss_items
'webref_rss_items' => array('id','title','description','link','guid','pubDate','author','category','comments','enclosure','source','chan_id')
),
'db_danaldo' => array(
//code here
),
'frontacc' => array(
//code here
)
[array][db][table][field]
As you can see, the database currently populated refers to an RSS project I am working on - one table for Channels, another for Items in that channel, at the moment that is another issue ('Users' table for now is not important)..
what I want to do is to return the array/sub-array names and convert each into variables for use as part of a string in an SQL Query, also need an alias for the tables I need to connect with:
(e.g. SELECT * FROM 'webref_rss_items' WHERE 'chan_id' = 'test.webref_rss_details.id')
where 'webref_rss_items' is a variable, 'chan_id' is a variable and 'test.webref_rss_details.id' are 3 variables in a concatenated string, although I've heard the concatenation in an SQL Query is not good practice, security-wise.. the strange thing is of all of those values, all I can retreive is the deepest level, 'id':
echo "{$da_db['test']['webref_rss_details'][0]}"
but get 'Array' returned or the last value of an array when I try to access the names!!
The reason for this is that the PHP file with the query will be within the 'public' part of the server and would like to have use variables with have no connotation to the original name(s), also it seems more convenient as the variables can be interchangable and I won't be using the same path all the time.
EDIT: My idea is to get key names from ['db'] to ['field']. The closest I have reached is to iterate keys and array_fill in a foreach loop, use range() inside another foreach, array_combine both then var_dump combined array like so:
foreach($da_db['test'] as $key1 => $val) { //put key-names into array1 to use as values
$a = array();
$a = array_fill(0, 1, $key1);
print($key1.'<br />');
}
foreach (range(0, 2) as $number) { //array for numbers to use as keys
$b = array();
$b = array_fill(0, 1, $number);
echo $number.'<br />';
}
$c = array_combine($b, $a); //combine both for new array
print_r($c.'<br />');
I could the use array_slice to get the name I want! (long winded?)
The problem is that the result of this only shows the last key => value; depending on command(print_r, print, echo), it shows:
[2] => webref_rss_items
OR
Array.
I hope that is enough info for now.
I've seen similar questions on here, but normally apply to one value, or one level of an array, but if you have seen this question before please advise and point me in right direction.
Your two top level arrays (db name and table name) are "named-key" arrays. The field level array (value of table name array) is an "integer key" array. PHP automatically adds numerical indexes for arrays that are defined with values only. For "named-key" arrays, you can only access their values by using the key name you defined.
For example:
$array1 = array('zero', 'one', 'two');
echo $array1[2]; // two
$array2 = array('zero' => 'this is zero', 'one' => 'this is one');
echo $array2['zero']; // this is zero
echo $array2[0]; // undefined
PHP provides a function called array_keys() that will return you an integer index array with all the key names. So you access your table array using an integer value, you can do this.
$da_db_test_keys = array_keys($da_db['test']);
echo $da_db_test_keys[1];
Maybe this will help you a little bit. I wasn't 100% on how you planned on accessing the values in your arrays, so if you have any more questions please try to clarify that part.
Related
I've been doing here some name processor, and I've run into small, kind of noob-ish problem.
I have CSV file with names and status, filters them only by 'Cool Ones" status, then i'm querying SQL, and getting another list of names that i have entered manually.
So here is code example, where i'm taking CSV file, filter, querying SQL, then it creates array, merges it and sorts alphabetically.
$nameFile = "names/$eid.csv";
$content = array_map('str_getcsv', file($nameFile));
$filteredData = array_filter($content, function($v){
return $v['1'] === 'Cool Ones'; },ARRAY_FILTER_USE_BOTH); //because in this file there are also 'Not Cool Ones'
$freePeople = array();
$sth = $DBcon->prepare("SELECT guestName, guestType FROM guestList WHERE forEvent = '$eid' ORDER BY 'guestName'");
$sth->execute();
$result2 = $sth->fetchAll(PDO::FETCH_NUM);
$listNames = array();
foreach($result2 as $row) {
$listNames[] = $row['0'];
$freeGuestName = $row['0'];
$freeGuestType = $row['1'];
}
$merged = array_merge($filteredData, $result2);
$sortedGuests = usort($merged, "sortGuestNames");
so my problem lies, that when outputing array, I'm getting duplicate results,
[50] => Array
(
[0] => John Down
[1] => Best Ones
)
[51] => Array
(
[0] => John Down
[1] => Cool Ones
)
Dunno what's next - i want that if my queried name is same as in this first CSV file, then hide this one, and show mine.
i was trying to unset key with
foreach($merged[$i]['0'] as $key => $value) {
if (in_array($merged[$i]['0'], $value)) {
unset($merged[$i]['0'][$key]);
}
}
but no luck, still outputing duplicates.
You can suggest better approach.
I've thought - maybe open CSV, query SQL and find my manual names - look up in opened CSV fields, append my status there, merge and push them to SQL database or new CSV file, where it could be outputted.
Thanks a lot!
A few things,
The thing we need to do is merge both arrays, but control which one overwrites the other. I am not sure if what you have does that now (in a reliable way) but one way to do that is to build 2 arrays. Both with the same structure, and the key as your unique field so we want this:
$csv = ['John Down' => ['John Down','Best Ones']];
$db = ['John Down' => ['John Down','Cool Ones']];
Then when we do array merge, the second argument will overwrite the first. So if we do
$csv = ['John Down' => ['John Down','Best Ones']];
$db = ['John Down' => ['John Down','Cool Ones']];
print_r(array_merge($csv, $db));
echo "\n";
print_r(array_merge($db, $csv));
Output:
// print_r(array_merge($csv, $db));
Array
(
[John Down] => Array
(
[0] => John Down
[1] => Cool Ones
)
)
//print_r(array_merge($db, $csv))
Array
(
[John Down] => Array
(
[0] => John Down
[1] => Best Ones
)
)
Sandbox
As you can see we can control which array is overwritten by the order we send them to array_merge in. The second one (or right one) overwrites the one to the left. So simply it reads from left to right.
So now what's the easiest way to get that structure from the DB? In PDO we can use FETCH_GROUP which takes the first column in the query and uses it as the top level key.
$sth = $DBcon->prepare("SELECT guestName, guestType FROM guestList WHERE forEvent = :eid GROUP BY guestName ORDER BY guestName");
//-- add `GROUP BY guestName` we don't want duplicates anyway
//-- no quotes see: ... ORDER BY 'guestName');
//-- use prepared statements
$sth->execute(['eid'=>$eid]);
$result2 = $sth->fetchAll(PDO::FETCH_NUM);
$result2 = array_column($result2, null, 0);
For the CSV you can build it that way when you read the file (by adding the key) and using fgetcsv or you can use this trick (also used above):
$csv = [['John Down','Best Ones']];
print_r(array_column($csv, null, 0));
Output
Array
(
[John Down] => Array
(
[0] => John Down
[1] => Best Ones
)
)
Sandbox
Which should give you basically what we need, then it's a simple matter of using array_merge.
One thing to mention is if your DB or CSV are not unique, you'll get some duplicate removal there too, you may have to account for.
Removing duplicates is fine, but you want to make sure to remove the correct duplicates in a repeatable and robust way. Using array_merge we can control that no mater the order the rows come in from the DB and the file.
Summery
So if we put this all together, this is all you should need:
$nameFile = "names/$eid.csv";
$content = array_map('str_getcsv', file($nameFile));
$filteredData = array_filter($content, function($v){
return $v['1'] === 'Cool Ones';
},ARRAY_FILTER_USE_BOTH); //because in this file there are also 'Not Cool Ones'
$sth = $DBcon->prepare("SELECT guestName, guestType FROM guestList WHERE forEvent = :eid GROUP BY guestName ORDER BY guestName");
$sth->execute(['eid'=>$eid]);
$result2 = $sth->fetchAll(PDO::FETCH_NUM);
$listNames = array_column($result2, 0);
$merged = array_merge(array_column($filteredData, null, 0), array_column($result2, null, 0));
$sortedGuests = usort($merged, "sortGuestNames");
So instead of adding code in patching over an issue, we went to the root cause and fixed it there and reduced the code by a few lines. This will work provided your CSV is in the correct format. guestName, guestType
Cheers!
http://php.net/manual/en/function.array-column.php
array_column ( array $input , mixed $column_key [, mixed $index_key = NULL ] ) : array
array_column() returns the values from a single column of the input, identified by the column_key. Optionally, an index_key may be provided to index the values in the returned array by the values from the index_key column of the input array.
input A multi-dimensional array or an array of objects from which to pull a column of values from. If an array of objects is provided, then public properties can be directly pulled. In order for protected or private properties to be pulled, the class must implement both the __get() and __isset() magic methods.
column_key The column of values to return. This value may be an integer key of the column you wish to retrieve, or it may be a string key name for an associative array or property name. It may also be NULL to return complete arrays or objects (this is useful together with index_key to reindex the array).
index_key The column to use as the index/keys for the returned array. This value may be the integer key of the column, or it may be the string key name. The value is cast as usual for array keys (however, objects supporting conversion to string are also allowed).
Assuming that you need unique user name, following is the solution.
Create a new blank users array.
Loop over the users array.
Append the users to new users array.
The key should be user name.
Hence, every time the same user comes, he will overwrite the previous one, removing duplicate.
Code:
$users = [
['John Down', 'Best Ones'],
['John Down', 'Cool Ones']
];
$newUsers = [];
if (! empty($users)) {
foreach ($users as $user) {
$newUsers[$user[0]] = $user[1];
}
}
echo '<pre>';print_r($newUsers);echo '</pre>';
// Output:
Array
(
[John Down] => Cool Ones
)
I solved my case:
I removed second key from merged array, then unserialize it, and mapped only unique ones! Everything is now working!
$input = array_map("unserialize", array_unique(array_map("serialize", $merged)));
Sometimes i really enjoy asking help for you, because it makes me think! To think deeper than ussual.
I am trying to update the variable $numberOfFoods in a foreach loop with the number of elements that each key holds in an associative array. Here is my code:
$foodsArray = array (
'France' => ['Souffle' , 'Baguette' , 'Fois gras'],
'England' => ['Bangers and mash' , 'Tea and biscuits'],
'America' => ['Hamburger', 'Steak and Eggs', 'Texas chili']
);
$countriesByCuisine = array();
foreach ($foodsArray as $originCountry => $countryAssocFood) {
$numberOfFoods = count(array_values($foodsArray));
for ($countryAssocFoodIndex = 0; $countryAssocFoodIndex < $numberOfFoods; $countryAssocFoodIndex++) {
$countriesByCuisine[$countryAssocFood[$countryAssocFoodIndex]] = $originCountry;
}
}
foreach (array_keys($countriesByCuisine) as $foodFromCountry) {
echo $foodFromCountry . ', From ' . $countriesByCuisine[$foodFromCountry] . '. ';
}
As it is, this code simply sets the $numberOfFoods variable to the integer 3, rather than updating the number to reflect the number of values that the current key holds. My overall goal with this code was to learn how to transform an array such that the values become keys in a new array, with those keys holding their previous keys as values. Please forgive my messy code, as I am pretty new to programming and PHP.
#Robbie Averill is right about array_flip to achieve you "overall goal" of flipping the keys and the values.
There are multiple, more efficient, ways to fix your current code, the best one probably being array_map, but I also want to provide you with why your current code is failing:
The issue is that you are counting $foodsArray for each iteration (and it's always equal to 3), instead of counting $countryAssocFood:
$numberOfFoods = count(array_values($countryAssocFood));
I got values of column A and B from Excel by below php code
for($i=1;$i<=$arrayCount;$i++)
{
$col_A = array(trim($allDataInSheet [$i]["A"]));
$col_B =array(trim($allDataInSheet [$i]["B"]));
}
If 'A' has 44 variable names and 'B' has 44 values.
In this scenario,How can I assign the values of 'B' to the variable names of 'A'
Please help me to solve this
Arrays in PHP can take on two different key-types and they can mix and match. Indexed by number and indexed by string. And an array can contain any value, including an array of values. This means that you can create an array that uses the names in Array A as the keys and the values in Array B as the values for those keys.
$columns = [];
// Arrays start at 0, but since these came from excel 0 is the column header.
// You want to stop 1 entry before the count of your array. Since arrays are 0 indexed, the array count is 1 larger than the last index.
for($i=1;$i<=$arrayCount-1;$i++)
{
$a = trim($allDataInSheet [$i]["A"]);
$b = trim($allDataInSheet [$i]["B"]);
// You don't need to specify the Array constructor anymore.
// You can just use brackets to create a new array.
// Not sure if you still want these, but I left them for you.
$col_A = [$a];
$col_B = [$b];
// Assign the values of B to columns in A
if(!isset($columns[$a]) {
$columns[$a] = $b;
} else {
// Debugging message - Tried to set two values to the same name.
}
}
// Do stuff with $columns
// $columns["a"] == "b"
Above, you can see that since $allDataInSheet[$i]["A"] is the string we want, we can just use that value as our key and its matching entry in B as the value for that key.
Notice how we don't let a value get added to the array if we already have that name set. If you want $columns[$a] to be an array of values, you can change it to look like this:
if(!isset($columns[$a]){
// If we don't have an entry for $columns[$a] create an array here to hold the values for possible $b's.
$columns[$a] = [];
}
// Add $b to the $columns[$a] array.
$columns[$a][] = $b;
That will treat the $columns array as an array of arrays. Meaning that each position can hold multiple values. So, we turn it into an array and just add the $b value to that position. If we come across that $a value again, we'll see that we already have that position set and we just use the array that's already there.
Notice - we do an isset check instead of an empty check because if 'b' was actually " " or false or 0 or for some strange reason, $columns[$a] doesn't change from an empty array to an array with something in it, than we don't want to erase the value that's already there.
Good Luck!
Question has been updated to clarify
For simple arrays, I find it convenient to use $arr[$key]++ to either populate a new element or increment an existing element. For example, counting the number of fruits, $arr['apple']++ will create the array element $arr('apple'=>1) the first time "apple" is encountered. Subsequent iterations will merely increment the value for "apple". There is no need to add code to check to see if the key "apple" already exists.
I am populating an array of arrays, and want to achieve a similar "one-liner" as in the example above in an element of the nested array.
$stats is the array. Each element in $stats is another array with 2 keys ("name" and "count")
I want to be able to push an array into $stats - if the key already exists, merely increment the "count" value. If it doesn't exist, create a new element array and set the count to 1. And doing this in one line, just like the example above for a simple array.
In code, this would look something like (but does not work):
$stats[$key] = array('name'=>$name,'count'=>++);
or
$stats[$key] = array('name'=>$name,++);
Looking for ideas on how to achieve this without the need to check if the element already exists.
Background:
I am cycling through an array of objects, looking at the "data" element in each one. Here is a snip from the array:
[1] => stdClass Object
(
[to] => stdClass Object
(
[data] => Array
(
[0] => stdClass Object
(
[name] => foobar
[id] => 1234
)
)
)
I would like to count the occurrences of "id" and correlate it to "name". ("id" and "name" are unique combinations - ex. name="foobar" will always have an id=1234)
i.e.
id name count
1234 foobar 55
6789 raboof 99
I'm using an array of arrays at the moment, $stats, to capture the information (I am def. open to other implementations. I looked into array_unique but my original data is deep inside arrays & objects).
The first time I encounter "id" (ex. 1234), I'll create a new array in $stats, and set the count to 1. For subsequent hits (ex: id=1234), I just want to increment count.
For one dimensional arrays, $arr[$obj->id]++ works fine, but I can't figure out how to push/increment for array of arrays. How can I push/increment in one line for multi-dimensional arrays?
Thanks in advance.
$stats = array();
foreach ($dataArray as $element) {
$obj = $element->to->data[0];
// this next line does not meet my needs, it's just to demonstrate the structure of the array
$stats[$obj->id] = array('name'=>$obj->name,'count'=>1);
// this next line obviously does not work, it's what I need to get working
$stats[$obj->id] = array('name'=>$obj->name,'count'=>++);
}
Try checking to see if your array has that value populated, if it's populated then build on that value, otherwise set a default value.
$stats = array();
foreach ($dataArray as $element) {
$obj = $element->to->data[0];
if (!isset($stats[$obj->id])) { // conditionally create array
$stats[$obj->id] = array('name'=>$obj->name,'count'=> 0);
}
$stats[$obj->id]['count']++; // increment count
}
$obj = $element->to->data is again an array. If I understand your question correctly, you would want to loop through $element->to->data as well. So your code now becomes:
$stats = array();
foreach ($dataArray as $element) {
$toArray = $element->to->data[0];
foreach($toArray as $toElement) {
// check if the key was already created or not
if(isset($stats[$toElement->id])) {
$stats[$toElement->id]['count']++;
}
else {
$stats[$toElement->id] = array('name'=>$toArray->name,'count'=>1);
}
}
}
Update:
Considering performance benchmarks, isset() is lot more faster than array_key_exists (but it returns false even if the value is null! In that case consider using isset() || array_key exists() together.
Reference: http://php.net/manual/en/function.array-key-exists.php#107786
What does the => operator mean in the following code?
foreach ($user_list as $user => $pass)
The code is a comment at PHP.net.
The user does not specify the value of $user_list, $user or $pass.
I normally see that => means equal or greater than.
However, I am not sure about its purpose here because it is not assigned.
I read the code as
process a list of users in integers
such that the value of each user is equal or greater than password
The above does not make sense to me.
=> is the separator for associative arrays. In the context of that foreach loop, it assigns the key of the array to $user and the value to $pass.
Example:
$user_list = array(
'dave' => 'apassword',
'steve' => 'secr3t'
);
foreach ($user_list as $user => $pass) {
echo "{$user}'s pass is: {$pass}\n";
}
// Prints:
// "dave's pass is: apassword"
// "steve's pass is: secr3t"
Note that this can be used for numerically indexed arrays too.
Example:
$foo = array('car', 'truck', 'van', 'bike', 'rickshaw');
foreach ($foo as $i => $type) {
echo "{$i}: {$type}\n";
}
// prints:
// 0: car
// 1: truck
// 2: van
// 3: bike
// 4: rickshaw
It means assign the key to $user and the variable to $pass
When you assign an array, you do it like this
$array = array("key" => "value");
It uses the same symbol for processing arrays in foreach statements. The '=>' links the key and the value.
According to the PHP Manual, the '=>' created key/value pairs.
Also, Equal or Greater than is the opposite way: '>='. In PHP the greater or less than sign always goes first: '>=', '<='.
And just as a side note, excluding the second value does not work like you think it would. Instead of only giving you the key, It actually only gives you a value:
$array = array("test" => "foo");
foreach($array as $key => $value)
{
echo $key . " : " . $value; // Echoes "test : foo"
}
foreach($array as $value)
{
echo $value; // Echoes "foo"
}
Code like "a => b" means, for an associative array (some languages, like Perl, if I remember correctly, call those "hash"), that 'a' is a key, and 'b' a value.
You might want to take a look at the documentations of, at least:
foreach
arrays
Here, you are having an array, called $user_list, and you will iterate over it, getting, for each line, the key of the line in $user, and the corresponding value in $pass.
For instance, this code:
$user_list = array(
'user1' => 'password1',
'user2' => 'password2',
);
foreach ($user_list as $user => $pass)
{
var_dump("user = $user and password = $pass");
}
Will get you this output:
string 'user = user1 and password = password1' (length=37)
string 'user = user2 and password = password2' (length=37)
(I'm using var_dump to generate a nice output, that facilitates debuging; to get a normal output, you'd use echo)
"Equal or greater" is the other way arround: "greater or equals", which is written, in PHP, like this; ">="
The Same thing for most languages derived from C: C++, JAVA, PHP, ...
As a piece of advice: If you are just starting with PHP, you should definitely spend some time (maybe a couple of hours, maybe even half a day or even a whole day) going through some parts of the manual :-)
It'd help you much!
An array in PHP is a map of keys to values:
$array = array();
$array["yellow"] = 3;
$array["green"] = 4;
If you want to do something with each key-value-pair in your array, you can use the foreach control structure:
foreach ($array as $key => $value)
The $array variable is the array you will be using. The $key and $value variables will contain a key-value-pair in every iteration of the foreach loop. In this example, they will first contain "yellow" and 3, then "green" and 4.
You can use an alternative notation if you don't care about the keys:
foreach ($array as $value)
Arrays in PHP are associative arrays (otherwise known as dictionaries or hashes) by default. If you don't explicitly assign a key to a value, the interpreter will silently do that for you. So, the expression you've got up there iterates through $user_list, making the key available as $user and the value available as $pass as local variables in the body of the foreach.
$user_list is an array of data which when looped through can be split into it's name and value.
In this case it's name is $user and it's value is $pass.