I want to check if uri segment($sef) is in array, before sending id to database.
And I want to ask which solution is better, or if is there something better.
Here are examples of how I tried to search the array
1)
if(array_search($sef, array_column($array,'sef'))) {
//find id and send it to DB
} else {
//wrong sef
}
2)
foreach($array as $k => $v) {
if( in_array($sef, $v)) {
return $v['id']; break;
} else {
//wrong sef
}
}
this is example of array
Array
(
[0] => Array
(
[sef] =>some-sef1
[id] => 39
)
[1] => Array
(
[sef] => some-sef2
[id] => 20
)
[2] => Array
(
[sef] => some-sef3
[id] => 38
)
Thanks for answers!
It depends on situation. For small size array, both of them will almost take same time.
1) If it's a small array, you can do it using in_array.
2) If it's a large array, You should use first one. Because a foreach will take more time to execute than array_search.
Both ways are almost the same, so it's a preference choice.
There are some tweaks possible though. First:
$sef_ids = array_column($array, 'id', 'sef');
if (isset($sef_ids[$sef])) { $id = $sef_ids[$sef]; ... }
Second:
foreach ($array as $k => $v) {
if ($v['sef'] === $sef) { $id = $v['id']; ... }
}
Now first one looks faster (didn't check), but it's still micro optimization unless you work with large arrays. I would aim for having $sef_ids data structure to work with from the beginning then.
Related
I have a post array and need to create a new array format from this to store in database with batch insert. I have achieved it with the following code. But want a better solution (if any) to achieve my array. I wanted to eliminate the inner loop but did not get any solution. Please provide any suggestion on how can I achieve this.
Code to parse array:
if ($this->input->post()) {
foreach ($this->input->post() as $key => $value) {
$i = 0;
/* need to eliminate this loop */
foreach ($value as $k => $v) {
$postData[$i][$key] = $v;
$i++;
}
}
}
Input array:
Array
(
[category_id] => Array
(
[0] => 1
[1] => 4
)
[pay_type_id] => Array
(
[0] => 2
[1] => 5
)
[frequency_id] => Array
(
[0] => 3
[1] => 6
)
)
Output array;
Array
(
[0] => Array
(
[category_id] => 1
[pay_type_id] => 2
[frequency_id] => 3
)
[1] => Array
(
[category_id] => 4
[pay_type_id] => 5
[frequency_id] => 6
)
)
If you really want to, you can do this without loops at all:
$input = $this->input->post();
$keys = array_keys($input);
$postData = [
array_combine($keys, array_column($input, 0)),
array_combine($keys, array_column($input, 1)),
];
This will give the same $postData output as your example, assuming that the input only has keys 0 and 1 in the inner arrays, as it does in your example. If the number of possible elements in the inner arrays is unknown, then you may need to introduce a loop on that, but the secondary loop can still be avoided.
I had to use array_combine() as well as array_column() as array_column() on it's own does not preserve the named keys the your top level of your array.
Other solutions using array_map() or array_walk() may also exist.
However, while it's short and concise, it isn't exactly clear for a reader to understand what it's doing, so unless you document it clearly, you'll be creating a maintenance headache for yourself in the long term.
The double-loop is a more readily understandable solution, pretty standard, and won't cause you any issues. So while I've given you a solution, I would actually recommend just using the code you've got.
Because you have two arrays, a:"records" and b:"fields" in any case, theoretically, you need to have at least two loops to populate the "records" and "fields" inside a record. And, basically, this is not a bad approach or a problem.
If you really want just one loop, because of faith reasons, you need to put a hard-coded list of field assignments in first loop that populate the records.
The only way I can see to do it without a second array is like this:
$arr = array("category_id" => array(1, 4), "pay_type_id" => array(2, 5), "frequency_id" => array(3, 6));
foreach ($arr as $key => $value) {
$postData[0][$key] = $value[0];
$postData[1][$key] = $value[1];
}
print_r($postData);
But you lose flexibility with this approach, because you have to know in advance how many indexes there will be in the inner arrays. The only way to make it generic enough to cope with changes in data is to use an inner loop similar to how you did it originally.
There's nothing much wrong with your original code, it's a pretty standard and reasonable approach to changing the array format in this scenario. It shouldn't give you any particular performance issues, even with fairly large arrays, and there's not really any neater way to approach it.
As per your ouput you need second loop also. But yes you can eliminate use of $i you can use $k instead.
You can change your code as:
if ($this->input->post()) {
foreach ($this->input->post() as $key => $value) {
foreach ($value as $k => $v) {
$postData[$k][$key] = $v;
}
}
}
DEMO
I have converted a CSV to a two dimensional array where the following array structure stores the column and row data
$table['status'] = ['active', 'active', 'inactive'];
$table['plan'] = ['annual', 'weekly', 'weekly '];
$table['spend'] = ['12,000', '19,000', '0' ];
print_r($table);
would appear as follows:
( [status] => Array ( [0] => active [1] => active [2] => inactive )
[plan] => Array ( [0] => annual [1] => weekly [2] => weekly )
[spend] => Array ( [0] => 12,000 [1] => 19,000 [2] => 0 ) )
I want to use native PHP array functions to query the arrays without having to write loops with nested conditions. If this was a MySQL database and I wanted to find the sum of spend from accounts with active status and weekly plans I would simply run the following query
SELECT SUM('Spend') FROM table WHERE status = 'Active' AND plan = 'Weekly';
But instead I have to take the following approach using a for loop
for ($index = 1; $index < count($table); $index++){
if (($table['status'][$index] == 'active') && ($table['plan'][$index] == 'weekly')){
$spend[$index] = $table['spend'][$index];
}
}
echo array_sum($spend);
This approach gives me a headache. Is there an obvious solution for refactoring this into php's native array functions or is a mess of explicit loops inevitable?
There aren't any native functions to do what you want. What's wrong with storing the information from the CSV files into a database?
If that's simply not an option then try foreach loops, they're much cleaner.
$spend = array();
foreach ($table['spend'] as $key => $amount)
{
if ($table['status'][$key] == 'active' && $table['plan'][$key] == 'weekly')
{
$spend[] = $amount;
}
}
Whilst it doesn't solve the loops issue it does help clean them up so you don't lose your mind so much.
Using Array Keys to get all "active" keys, then loop through only those to find the matches.
$keys = array_keys($table['status'], 'active');
foreach($keys as $key)
{
if($table['plan'][$key] == 'weekly')
{
$spend[] = $table['spend'][$key];
}
}
print_r($spend);
Spend:
Array
(
[0] => 19,000
)
this is pretty messy but I found one way of doing it
$keys = array_intersect(array_keys($table['status'], 'active'), array_keys($table['plan'], 'weekly'));
$subs['total'] = array_intersect_key($table['spend'], array_flip($keys));
print_r(array_sum($subs['total']));
$wp->get_results will return an array and formats the array depends if the second parameter is specified; if not, it is default to an object, right? But my question is it possible to retrieve results then store it the an array? Like this $arr = array(1,2,3,4,5)? What my main concern is this.. I want to search in the array if the value is present.
Now I can't do a in_array if the returned results is like this.
$arr = array(array('1'), array('2'), array('3'), array('4'), array('5'));
Any help would be much appreciated. Thanks.
EDITED
my $arr would look like this
Array ( [0] => stdClass Object ( [code] => 8 [id] => ) [1] => stdClass Object ( [code] => 1 [id] => ) )
EDITED
Found a solution:
if (in_array(array('1'), $arr) {
// found value
}
You can not match directly, for matching, it you will have to do something like this :
$arr = array(array('1'), array('2'), array('3'), array('4'), array('5'));
foreach($arr as $newar)
{
if (in_array('2',$newar))
{
echo 'hello';
}
}
I'm not really following the problem here, but assuming you want to find a specific value inside the wpdb results......
foreach($arr as $key => $row) {
if($row->code == $VALUE_YOU_WANT_TO_MATCH) {
// do something
break;
}
}
Note: $arr is an array of objects, its not a multidimensional array.
say for example I want to check if if code = 1 exist in my result.
foreach($arr as $myarr){
if ($myarr->code == "1"){
echo "record was found\n";
break;//this line makes the foreach loop end after first success.
}
}
I want to check only the value [id] for duplicates, and remove all keys where this "field" [id] is a duplicate.
Example: If I have numbers 1,2,1. I want the result to be 2, not 1,2. And criteria for duplicates is determined only by checking [id], not any other "field".
Original array:
Array
(
[0] => Array
(
[name] => John
[id] => 123
[color] => red
)
[1] => Array
(
[name] => Paul
[id] => 958
[color] => red
)
[2] => Array
(
[name] => Jennifer
[id] => 123
[color] => yellow
)
)
The result I want:
Array
(
[0] => Array
(
[name] => Paul
[id] => 958
[color] => red
)
)
I agree with everyone above, you should give us more information about what you've tried, but I like to code golf, so here's a completely unreadble solution:
$new_array = array_filter($array, function($item) use (&$array){
return count(array_filter($array, function($node) use (&$item){
return $node['id'] == $item['id'];
})) < 2;
});
This should be fairly easy to accomplish with a couple of simple loops:
set_time_limit(0); // Disable time limit to allow enough time to process a large dataset
// $items contains your data
$id_counts = array();
foreach ($items as $item) {
if (array_key_exists($item['id'], $id_counts)) {
$id_counts[$item['id']]++;
} else {
$id_counts[$item['id']] = 1;
}
}
for ($i = count($items); $i >= 0; $i--) {
if ($id_counts[$items[$i]['id']] > 1) {
array_splice($items, $i, 1);
}
}
Result:
Array
(
[0] => Array
(
[name] => Paul
[id] => 958
[color] => red
)
)
While there are neater ways to do it, one advantage of this method is you're only creating new arrays for the list of ids and duplicate ids and the array_splice is removing the duplicates from the original array, so memory usage is kept to a minimum.
Edit: Fixed a bug that meant it sometimes left one behind
This is a very basic approach to the answer and I am sure there are much better answers however I would probably start by doing it the way I would on paper.
I look at the first index, check its value. Then I go through every other index making note of their index if the value is the same as my originally noted value. Once I have gone through the list if I have more than one index with that particular value I remove them all (starting with the highest index, so as to not affect indexes of the others while deleting).
Do this for all other indexes till you reach the end of the list.
It is long winded but will make sure it removes all values which have duplicates. and leaves only those which originally had no duplicates.
function PickUniques(array $items){
// Quick way out
if(empty($items)) return array();
$counters = array();
// Count occurences
foreach($items as $item){
$item['id'] = intval($item['id']);
if(!isset($counters[$item['id']])){
$counters[$item['id']] = 0;
}
$counters[$item['id']]++;
}
// Pop multiples occurence ones
foreach($counters as $id => $occurences){
if($occurences > 1){
unset($counters[$id]);
}
}
// Keep only those that occur once (in $counters)
$valids = array();
foreach($items as $item){
if(!isset($items[$item['id']])) continue;
$valids[$item['id']] = $item;
}
return $valids;
}
Try this one :)
I'm having a bit of difficulty merging a multi-dimensional array based on 1 index. I don't know if I've just been racking my brain too long and have messed myself up or what, but I can't get this.
An example of 2 indices from 2 arrays is as such:
// Array1:
[0] => Array
(
[appID] => 58510
[name] => SomeRandomApp
[users] => Array
(
[0] => randomUser
)
)
// Array2:
[0] => Array
(
[appID] => 58510
[name] => SomeRandomApp
[users] => Array
(
[0] => anotherUser
)
)
// Desired Result:
[0] => Array
(
[appID] => 58510
[name] => SomeRandomApp
[users] => Array
(
[0] => randomUser
[1] => anotherUser
)
)
I'd like to merge based on "appID" and nothing else. And then do another merge on users so that if another index has different users, they all just merge.
It sounds like you want to get a list of users for each app. I think you will have to loop through them. You could created a result array indexed by the appID like this (not tested):
function app_users($array1, $array2) {
$combined = array ();
foreach (array($array1, $array2) as $arr) {
foreach ($arr as $values) {
if (!isset($combined[$values['appId']])) {
$combined[$values['appID']] = $values;
}
else {
$combined[$values['appID']]['users'][] = $values['users'][0];
}
}
}
}
$result = app_users($array1, $array2);
This assumes the same user won't be listed twice. You can modify the function to handle duplicates if necessary.
As a side note, array_merge will overwrite values in the first array with the second in the case of duplicate keys, which I don't believe is the behaviour you want here.
#Andrew, have you try to use array_merge_recursive() instead?
Finally got it all worked out.
$newArray = array();
foreach($data as $item)
{
$appID = $item['appID'];
$users = $item['users'];
unset($item['users']);
unset($item['hoursOnRecord']);
if(!isset($newArray[$appID]))
{
$newArray[$appID] = $item;
foreach($users as $user)
$newArray[$appID]['users'][] = $user;
}
else
{
$users2 = $newArray[$appID]['users'];
$newArray[$appID] = $item;
foreach($users as $user)
$newArray[$appID]['users'][] = $user;
foreach($users2 as $user)
$newArray[$appID]['users'][] = $user;
}
}
It's pretty sloppy, but it works, and it works pretty damn well if I do say so myself. Haven't benchmarked it yet but I did test it against a pretty heavy array with no real noticeable delay. There's a LOT more data in each index than what I'm showing. All in all, I'm content.
I hope this'll help someone else out.