I'm trying to add random numbers with array_push to an array in the field 'notes' => [] but I think I'm not doing it right since I do not see the random numbers stored in the array.
I am doing it in the following way:
$person1= [
'name' => 'person1',
'note' => []
];
$person2= [
'name' => 'person2',
'note' => []
];
$person3= [
'name' => 'person3',
'note' => []
];
$data=[$person1, $person2, $person3];
$_SESSION['data'] = $data;
function insertNumRandom(){
$data = $_SESSION['data'];
foreach ( $data as $student ) {
array_push($student['note'], rand(0,10));
}
}
function showNotes(){
foreach ( $data as $student ) {
echo implode($student['note']);
}
}
showNotes(); // To show the notes but it shows nothing.
You should change insertNumRandom like as below
function insertNumRandom(){
$data = $_SESSION['data'];
foreach ( $data as &$student ) {
array_push($student['note'], rand(0,10));
}
$_SESSION['data'] = $data;
}
showNotes function
function showNotes(){
$data = $_SESSION['data'];
foreach ( $data as $student ) {
echo implode($student['note']);
}
}
and call insertNumRandom before showNotes.
insertNumRandom();
showNotes();
You're referencing the $data with the "as" keyword which creates a new object.
You should instead iterate through the object you already have.
function insertNumRandom(){
$index = 0;
for($index = 0; $index<sizeof($data['data']); $index++ ) {
array_push($data[$index]['note'], rand(0,10));
}
}
try this maybe, still not sure how you're calling the insertNumRandom() function
function showNotes($arr){
foreach ( $arr as $student ) {
var_dump(implode($student['note']));
}
}
insertNumRandom();
showNotes($data);
you have a number of issues in your example.
First of all, the way you are using the $_SESSION object to pass some values to the function is not necessary, and not clean. You can either use global $data inside of the functions and they will suddenly have access to the $data variable from the parent scope. But even that is not very clean. I would suggest that you pass the data object by reference to the functions. That will make your function more portable and testable.
Your example is accessing the $student variable by value. All you need to do is to access it by reference by using the ampersand (&) in the foreach() like this foreach ( $data as &$student ) { ... }
I have noticed that you have never made a single call to insertNumRandom()
To have a better idea about what's in the arrays, I would suggest that you use a field separator for the implode() function and that you print a new line after imploding the array. I bet you will like the result.
Finally, just a word of advice ... array_push() lets you push one or more items in an array. But I personally use it only when I need to push multiple items in an array. For push just item new items, I use the short-hand $myArray[] = "new item";
So in practice, here is what your example will become ...
<?php
// Since you are not reusing $person1, $person2 and $person3 beyond the initialization
// phase, then let's keep things cleaner.
$data[] = [
'name' => 'person1',
'note' => []
];
$data[] = [
'name' => 'person2',
'note' => []
];
$data[] = [
'name' => 'person3',
'note' => []
];
/**
* In this function signature, the & means that the argument is passed by reference.
* That make it possible for the function to change the value of the argument.
*/
function insertNumRandom(&$theData) {
// The foreach() also needs to use $student by reference so that we can modify it
// by adding the random number to it.
foreach($theData as &$student) {
$student['note'][] = rand(0,10);
}
}
/**
* No need to pass $theData by reference because the function will not change its value.
*/
function showNotes($theData) {
// Here, the foreach() is using student by value because we do not need to change it's value.
foreach($theData as $student) {
echo implode($student['note'], ', ') . "\n";
}
}
// Inserting some random notes 3 times.
insertNumRandom($data);
insertNumRandom($data);
insertNumRandom($data);
showNotes($data); // To show the notes but it shows nothing.
?>
Related
I'm having trouble removing an object inside of this array.
First I get the $id that is to be removed from the array.
But when I'm filtering throw the array its appending keys to it.
So the logic ll no longer work on the rest of the application.
How can I maintain the same syntax on the options object after removing the object inside of the cart array ?
public function destroy( $id, Request $request )
{
$user = $this->user ;
$data = array_filter( $user->options->cart , function ( $option ) use ( $id ) {
if ( $option->product_id == $id ) {
return false;
}
return json_encode($option);
});
//dd($user->options->cart);
//dd($data);
$user->options = (object)['cart' => $data ];
$user->save() ;
return response()->json( $user , 200 ) ;
}
Solved :
public function destroy( $id, Request $request )
{
$user = $this->user ;
$data = array_filter( $user->options->cart , function ( $option ) use ( $id ) {
if ( $option->product_id == $id ) {
return false;
}
return true;
});
$user->options = ['cart' => array_values( $data ) ];
$user->save() ;
return response()->json( $user , 200 ) ;
}
}
if i understood u right , u want to rearrange the array after u do your logic plus keeping the structure , i would suggest you to use array_values
$new_data= array_values($data);
and if u got an error that its not an array although i doubt that just use the toArray() method
$new_data= array_values($data->toArray());
It seems like (object)['cart' => $data ] is somehow changing your array.
Setting the property directly should work:
$user->options->cart = $data;
Also, return json_encode($option); doesn't have any real effect except making the execution slower. You can just return true;.
Looking at your JSON encoding, I see that your options object on the bottom left is an object that contains a property, cart, which is an array. Your options object on the bottom right is an object that contains a property, cart, which is an object that contains a property for each numeric index.
I'm not at all certain, but I think the problem might be that the array_filter function preserves the array keys:
If the callback function returns TRUE, the current value from array is returned into the result array. Array keys are preserved.
I suggest you try using some approach that does not try to preserve array keys so that your filtered array has contiguous, numeric values.
public function destroy( $id, Request $request )
{
foreach($this->user->options->cart as $key => $cart_item) {
if ($cart_item->product_id == $id) {
unset($this->user->options->cart[$key]);
}
}
$user->save() ;
return response()->json( $user , 200 ) ;
}
EDIT: I am not privy to the details of your implementation (I don't know what type of object $user is or what $user->save or $response->json() might do) but this code will remove an array element by product_id:
$arr = array(
(object)["product_id" => 819, "name" => "I am 819"],
(object)["product_id" => 820, "name" => "I am 820"],
(object)["product_id" => 821, "name" => "I am 821"],
(object)["product_id" => 822, "name" => "I am 822"]
);
foreach($arr as $key => $v) {
if ($v->product_id == 820) {
unset($arr[$key]);
}
}
var_dump($arr);
I have a database with a couple of tables related between them. For example, the table User contains all the users in the system.
Then I have an index table named User_friend with the relation between a user an it's friends.
I have a function loadObject($class, $id) which is called like:
loadObject('User', 1);
and returns the User with id = 1 as an array with the following format:
array(
'id' => 1,
'username' => 'My user',
// the following array contains all the entries in User_invited
'friends' => [2, 3, 4, 5],
// same for comments
'comments' => [6, 7]
'type' => 'User'
);
I'm trying to come up with a recursive function that checks the User with id = 1, finds all the friends (inside the 'friends' array) and then loops through each value, find those Users and it's friends until it reaches the end of the chain without duplicating any entries.
This seems pretty straight forward. The problem is that apart from friends we can have other relations with Comments, Events and many other tables.
The tricky part is that this function should not only work with the 'User' class, but also with any class we define.
What I'm doing is using some sort of Indexed array to define which index tables refer to which main tables.
For example:
$dependencies = [
'friends' => 'User'
];
This means that, when we find the 'friends' key, we should query the 'User' table.
Here's my code:
<?php
$class = $_GET['class'];
// if we receive a collection of ids, find each individual object
$ids = explode(",", $_GET['ids']);
// load all main objects first
foreach($ids as $id) {
$error = isNumeric($id);
$results[] = loadObject($class,$id);
}
$preload = $results;
$output = [];
$output = checkPreload($preload);
print json_encode($output);
function checkPreload($preload)
{
$dependencies = [
'comment' => 'Comment',
'friend' => 'User',
'enemy' => 'User',
'google' => 'GoogleCalendarService',
'ical' => 'ICalCalendarService',
'owner' => 'User',
'invited' => 'User'
];
foreach($preload as $key => $object)
{
foreach($object as $property => $values)
{
// if the property is an array (has dependencies)
// i.e. event: [1, 2, 3]
if(is_array($values) && count($values) > 0)
{
// and if the dependency exists in our $dependencies array, find
// the next Object we have to retrieve
// i.e. event => CatchAppCalendarEvent
if(array_key_exists($property, $dependencies))
{
$dependentTable = $dependencies[$property];
// find all the ids inside that array of dependencies
// i.e. event: [1, 2, 3]
// and for each ID load th the object:
// i.e. CatchAppCalendarEvent.id = 1, CatchAppCalendarEvent.id = 2, CatchAppCalendarEvent.id = 3
foreach($values as $id)
{
$dependantObject = loadObject($dependencies[$property], $id);
// if the object doesn't exist in our $preload array, add it and call the
// function again
if(!objectDoesntExist($preload, $dependantObject)) {
$preload[] = $dependantObject;
reset($preload);
checkPreload($preload);
}
}
}
}
}
}
return $preload;
}
// 'id' and 'type' together are unique for each entry in the database
function objectDoesntExist($preload, $object)
{
foreach($preload as $element)
{
if($element['type'] == $object['type'] && $element['id'] == $object['id']) {
return true;
}
}
return false;
}
I'm pretty sure I'm close to the solution but I'm not able to understand why is not working. Seems to get stuck in an infinite loop even if I'm using a function to check if the object has been inserted in the $preload array. Also, sometimes doesn't check the next set of elements. Could it be because I'm appending the data to the $preload variable?
Any help is more than welcome. I've been trying to find algorithms for resolving dependencies but nothing applied to MySQL databases.
Thanks
After some failed tests I've decided to not use a recursive approach but an iterative approach.
What I'm doing is start with one element and put it in a "queue" (an array), find the dependencies for that element, append them to the "queue" and then step back and re-check the same element to see if there are any more dependencies.
The function to check the dependencies is a bit different now:
/**
* This is the code function of our DRA. This function contains an array of dependencies where the keys are the
* keys of the object i.e. User.id, User.type, etc. and the values are the dependent classes (tables). The idea
* is to iterate through this array in our queue of objects. If we find a property in one object that that matches
* the key, we go to the appropriate class/table (value) to find more dependencies (loadObject2 injects the dependency
* with it's subsequent dependencies)
*
*/
function findAllDependenciesFor($element)
{
$fields = [
'property' => 'tableName',
...
];
$output = [];
foreach($element as $key => $val) {
if(array_key_exists($key, $fields)) {
if(is_array($val)) {
foreach($val as $id) {
$newElement = loadObject($fields[$key], $id);
$output[] = $newElement;
}
}
else {
// there's been a field conversion at some point in the app and some 'location'
// columns contain text and numbers (i.e. 'unknown'). Let's force all values to be
// and integer and avoid loading 0 values.
$val = (int) $val;
if($val != 0) {
$newElement = loadObject($fields[$key], $val);
$output[] = $newElement;
}
}
}
}
return $output;
}
I'm also using the same function as before to check if the "queue" already contains that element (I have renamed the function to be "objectExists" instead of "objectDoesntExist". As you can see I check the type (table) and the id because the combination of these two properties is unique for the whole system/database.
function objectExists($object, $queue)
{
foreach($queue as $element) {
if($object['type'] == $element['type'] && $object['id'] == $element['id']) {
return true;
}
}
return false;
}
Finally, the main function:
// load all main objects first
foreach($ids as $id) {
$error = isNumeric($id);
$results[] = loadObject($class,$id);
}
$queue = $results;
for($i = 0; $i < count($queue); $i++)
{
// find all dependencies of element
$newElements = findAllDependenciesFor($queue[$i]);
foreach($newElements as $object) {
if(!objectExists($object, $queue)) {
$queue[] = $object;
// instead of skipping to the next object in queue, we have to re-check
// the same object again because is possible that it included new dependencies
// so let's step back on to re-check the object
$i--;
}
}
$i++;
}
As you can see, I'm using a regular "for" instead of a "foreach". This is because I need to be able to step forward/backward in my "queue".
I have this object:
$myobject = (object) [
'name' => [],
'value' => [],
'id' => [],
];
I want to add some values in a for each loop, but array push does not seem to work.
I've tried this:
$object_name = $myobject->name;
array_push($object_name, "testName");
I've looked everywhere but can't seem to find the answer.
You cann't use array_push this way. $object_name is not your main object.
When you push to $object_name, your $myobject is still empty.
You can fix it adding reference &, for example:
$object_name = &$myobject->name;
or just push to your original object:
array_push($myobject->name, "testName");
or
$myobject->name[] = "something";
Simple option is to add another item to the property using normal array notation.
e.g.
$object->name[] = 'testName';
Try this:
$names = ['A', 'B', 'C']; /* This is an array of names */
foreach ($names as $name) {
$myobject->name[] = $name;
}
echo '<pre>';
print_r($myobject);
I want to make a foreach loop like this one
foreach ($this->data['array'] as $this->data['key'] => $this->data['value'])
{
echo $this->data['value'];
}
Yet the $this->data['value'] is never created. Why is this and what am I doing wrong?
In my understanding, you have a class in which there is a variable or array name $data.
Now, you added an array in $data with an index named 'array', right?
If so, this code will work properly -
class myClass{
public $data = array(); //$data is an array
function print_array(){
foreach ($this->data['array'] as $this->data['key'] => $this->data['value'])
{
echo $this->data['value'];
}
}
}
$ob = new myClass(); // object declaration for your class
array_push($ob->data,'array'); // added a value to the $data array.
$ob->data['array'] = array(); // the newly added value is declared as an index of an array
// Now simply push values to the array named $data['array']
array_push($ob->data['array'],1);
array_push($ob->data['array'],2);
array_push($ob->data['array'],3);
$ob->print_array(); // call the print_array() function. $this will be passed to that function
Hope this will help to understand.
If you still have problem, please comment.
To have a clear understanding, you can visit this link. There are lots of simple and interesting examples explained!
Happy Coding!
I think $this is for current class object reference not for an array
foreach ($this->data['array'] as $k => $v)
{
echo $v;
$this->data['key'][] = $k;
$this->data['value'][] = $v;
}
print_r($this->data['key']);
print_r($this->data['value']);
If:
class YourClass {
private data = array(
'array' => array(
'key1' => 'val1',
'key2' => 'val2', etc.
)
);
then it should be:
foreach ($this->data['array'] as $key => $val)
{
echo $val;
// if you want to add keys and vals to data array:
$this->data[$key] = $val;
}
This may be some sort of weird longer shortcut, and please correct me if I'm mistaken in this train of thought...
I have a matrix of data that looks like:
unique_id | url | other random data...
unique_id | url | other random data...
unique_id | url | other random data...
I want to be able to reference an item by either it's url, or it's unique_id - is there a fancy way to do this?
I suppose the cheating solution would be to just make two arrays, but I was wondering if there is a better way.
Only way I can think of that doesn't involve iterating the array for each search (see Jacob's answer) is to store references to each item in two arrays.
Edit: As the URLs and IDs cannot collide, they may be stored in the same reference array (thanks Matthew)
$items; // array of item objects
// Use objects so they're implicitly passed by ref
$itemRef = array();
foreach ($items as $item) {
$itemRef[$item->unique_id] = $item;
$itemRef[$item->url] = $item;
}
// find by id
$byId = $itemRef[$id];
// find by url
$byUrl = $itemRef[$url];
You could probably encapsulate this nicely using a collection class that implements getById() and getByUrl(). Internally, it could store the references in as many arrays as is necessary.
Of course, what you're essentially doing here is creating indexed result sets, something best left to database management systems.
Try something like this:
function selectByIdOrURL($array, $data) {
foreach($array as $row) {
if($row['unique_id'] == $data || $row['url'] == $data) return $row;
}
return NULL;
}
$array = array(
array('unique_id' => 5, 'url' => 'http://blah.com'),
array('unique_id' => 3, 'url' => 'http://somewhere_else.com')
);
$found = selectByIdOrURL($array, 5); //array('unique_id' => 5, 'url' => 'http://blah.com')
$nfound = selectByIdOrURL($array, 10); //NULL
It appears your fancy solution was only available as of PHP 5.5.
You can combine the use of array_search and array_column to fetch your entry in a single line of code:
$items = [
[
'unique_id' => 42,
'url' => 'http://foo.com'
],
[
'unique_id' => 57,
'url' => 'http://bar.com'
],
[
'unique_id' => 36,
'url' => 'http://example.com'
],
];
$bar = $entries[array_search(57, array_column($items, 'unique_id'))];
var_dump($bar);
//outputs
array (size=2)
'unique_id' => int 57
'url' => string 'http://bar.com' (length=14)
Surely an object would be the easy way?
class Item {
public $unique_url;
public $url;
public $other_data;
public function __construct($unique_url, $url, $other_data)
{
$this->unique_url = $unique_url;
$this->url = $url;
$this->other_data = $other_data;
}
}
class ItemArray {
private $items = array();
public function __construct()
{
}
public function push(Item $item)
{
array_push($items, $item); //These may need to be reversed
}
public function getByURL($url)
{
foreach($items as $item)
{
if($item->url = $url)
{
return $item;
}
}
}
public function getByUniqueURL($url)
{
foreach($items as $item)
{
if($item->unique_url = $unique_url)
{
return $item;
}
}
}
}
Then use it with
$itemArray = new ItemArray();
$item = new Item("someURL", "someUniqueURL","some other crap");
$itemArray->push($item);
$retrievedItem = $itemArray->getItemByURL("someURL");
This technique has a little extra overhead due to object creation, but unless you're doing insane numbers of rows it would be fine.