I am trying to add 4 foreach into one. I know how to add 2 foreach into one like this :
foreach (array_combine($images, $covers) as $image => $cover) {
But i want to add more two foreach $titles as $title and $albums as $album.
I am not sure want like this :
foreach (array_combine($images, $covers) as $image => $cover) {
foreach (array_combine($titles, $albums) as $title => $album) {
echo "$image-$cover-$title-$album"
It show me duplicate of every output.I mean output is
demo-demo1-demo2-demo3demo-demo1-demo2-demo3
Need output only
demo-demo1-demo2-demo3
Put the for each statement in a function. Then create a loop that calls it.
public function loopMe($images, $covers)
{
foreach (array_combine($images, $covers) as $image => $cover) {
$this->loopMe($image,$cover);
}
}
It looks like your second for loop is being called multiple times per item in the first for loop. So you want to make sure that you are only calling the second for loop once per image cover. or set an index cap on the second for loop. For instance if you are tyring to map the first item in the first for loop to the first item in the second for loop you should use an index.
public function loopMe($images)
{
for ($i = 0; $i < count($images); $i++) {
echo $images[$i] . '-'. $title[$i] . '-' . $cover[$i] . '-'. $album[$i];
}
}
I think you are approaching this problem from the wrong angle. From what I can tell, you are trying to output the properties of something. I think what you want to do is approach this from an object-oriented approach by creating a class and using a method to output the contents of your object.
Something like this:
class MyAlbumThing {
protected $image;
protected $cover;
protected $title;
protected $album;
public __construct($image, $cover, $title, $album) {
$this->image = $image;
$this->cover = $cover;
$this->title = $title;
$this->album = $album;
}
public getImage() {
return $this->image;
}
public getCover() {
return $this->cover;
}
public getTitle() {
return $this->title;
}
public getAlbum() {
return $this->album;
}
public getString() {
return $this->image . '-' .
$this->cover . '-' .
$this->title . '-' .
$this->album;
}
}
Then, you can instantiate this class and print your properties:
MyAlbumThing album = new MyAlbumThing("demo", "demo1", "demo2", "demo3");
echo $album->getString();
Would output:
demo-demo1-demo2-demo3
Also, if you hav a lot of these things, then you would use a foreach, like so:
$myAlbumArray = new array();
$myAlbumArray[] = new MyAlbumThing("demo", "demo1", "demo2", "demo3");
$myAlbumArray[] = new MyAlbumThing("anotherdemo", "anotherdemo1", "anotherdemo2", "anotherdemo3");
$lengthOfArray = sizeof(myAlbumArray);
for ($i = 0; $i < $lengthOfArray; $i++) {
echo $myAlbumArray[$i]->getString();
}
Sorry for any errors in my syntax, I wrote that in the browser without the help of my IDE.
I highly recommend learning more about object-oriented PHP programming. I found this article especially helpful while I was learning: http://code.tutsplus.com/tutorials/object-oriented-php-for-beginners--net-12762
EDIT:
Please mark this answer as correct if you did indeed find this helpful for your problem.
Related
I've a university project in which I've to print the relations between students in different classes level by level. The idea is if we have John and Kris studying in the same class they are friends of first level, if Kris studies with Math in same class then John and Math are friends of second level. I researched the problem and I found algorithms like this, but my main problem is that I use objects as input data :
<?php
class Student {
private $id = null;
private $classes = [];
public function __construct($id) {
$this->id = $id;
}
public function getId() {
return $this->id;
}
public function getClasses() {
return $this->classes;
}
public function addClass(UClass $class) {
array_push($this->classes, $class);
}
}
class UClass {
private $id = null;
private $students= [];
public function __construct($id) {
$this->id = $id;
}
public function getId() {
return $this->id;
}
public function getStudents() {
return $this->students;
}
public function addStudent(Student $student) {
array_push($this->students, $student);
$student->addClass($this);
}
}
function getRelations(Student $start_student, &$tree = array(), $level = 2, &$visited) {
foreach ($start_student>Classes() as $class) {
foreach ($class->Students() as $student) {
if($start_student->getId() != $student->getId() && !is_int(array_search($student->getId(), $visited))) {
$tree[$level][] = $student->getId();
array_push($visited, $student->getId());
getRelations($student, $tree, $level+1, $visited);
}
}
}
}
$class = new UClass(1);
$class2 = new UClass(2);
$class3 = new UClass(3);
$student = new Student(1);
$student2 = new Student(2);
$student3 = new Student(3);
$student4 = new Student(4);
$student5 = new Student(5);
$student6 = new Student(6);
$class->addStudent($student);
$class->addStudent($student2);
$class->addStudent($student4);
$class2->addStudentr($student2);
$class2->addStudent($student4);
$class2->addStudent($student5);
$class3->addStudent($student4);
$class3->addStudent($student5);
$class3->addStudent($student6);
$tree[1][] = $student->getId();
$visited = array($student->getId());
getRelations($student, $tree, 2, $visited);
print_r($tree);
I'm stuck at writing getRelations() function that should create an array that is something like
Array ( [1] => Array ( [0] => 1 ) [2] => Array ( [0] => 2 [1] => 4 ) [3] => Array ( [0] => 5 [1] => 6 ) )
but I can't get the recursion right(or probably the whole algorithm). Any help will be greatly appreciated.
The logic in your recursive procedure is not correct. Example:
Say you enter the procedure for some level A and there are actually 2 students to be found for a connection at that level.
You handle the first, assign the correct level A, mark him as "visited".
Then, before getting to the second, you process level A+1 for the first student. Somewhere in his "chain" you may also find the second student that was waiting to get handled at level A. However, he now gets assigned some higher level A+n, and is then marked as visited.
Next, when the recursion for student1 is finished, you continue with the second. However, he has already been "visited"...
(By the way, I do not quite understand (but my php is weak...) why your first invocation of GetRelations specifies level=2.)
Anyway, to get your logic right there's no need for recursion.
Add a property "level" to each student. Put all students also in an overall collection "population".
Then, for a chosen "startStudent", give himself level=0, all other students level=-1.
Iterate levels and try to fill in friendship levels until there's nothing left to do. My php is virtually non-existent, so I try some pseudo-code.
for(int level=0; ; level++) // no terminating condition here
{
int countHandled = 0;
for each (student in population.students)
{
if (student.level==level)
{
for each (class in student.classes)
{
for each (student in class.students)
{
if(student.level==-1)
{
student.level = level+1;
countHandled++;
}
}
}
}
}
if(countHandled==0)
break;
}
Hope this helps you out. Of course, you still have to fill in the tree/print stuff; my contribution only addresses the logic of assigning levels correctly.
I come up with that function(not sure if it's the best solution, but it works with the class objects)
function print_students(Student $start_student, &$tree = array(), $lvl = 1) {
if (!$start_student) {
return;
}
$tree[$lvl][] = $start_student->getId();
$q = array();
array_push($q, $start_student);
$visited = array($start_student->getId());
while (count($q)) {
$lvl++;
$lvl_students = array();
foreach ($q as $current_student) {
foreach ($current_student->getClasses() as $class) {
foreach ($class->getStudents() as $student) {
if (!is_int(array_search($student->getId(), $visited))) {
array_push($lvl_students, $student);
array_push($visited, $student->getId());
$tree[$lvl][] = $student->getId();
}
}
}
}
$q = $lvl_students;
}
}
My objective is to search a multidimentional array for a plot and output information about who is buried there.
My code is
function searchByPlot($plot, $array) {
foreach ($array as $key => $val) {
if ($val['plot'] === $plot) {
return $key;
}
}
return null;
}
function calculate() {
$id = searchByPlot('681', $ma);
$code = $ma[$id]['code'];
$last = $ma[$id]['h_last'];
$plot = $ma[$id]['plot'];
if (isset($last)){
echo 'ID: '.$id.' Code: '.$code.' Lastname'.$last.'';
}
echo "Test".$id."";
}
calculate();
However when i call the calculate function there is no response even though there is a result in the array.
When i call the searchByPlot function directly it works fine.
$id = searchByPlot('681', $ma);
echo $id;
However when i call the calculate function it doesn't work at all, nothing is outputted on $id as you can see my test call above.
echo $id;
Can you help please?
Many thanks, Buster
Right now I'm trying to write a function that would allow me to access member functions. The code in question looks a little like this:
protected $formName;
protected $formClass;
protected $formAction;
protected $formMethod;
protected $formObjArray = array(); //outputs in order. So far it should only take newLine, selectTag, inputTag, textTag.
protected $submitBtnVal;
protected $encType;
function __construct($args) {
$this->formName = $args['formName'];
$this->formAction = $args['formAction'];
if (isset($args['formClass'])) $this->formClass = $args['formClass'];
if (isset($args['encType'])) $this->encType = $args['encType'];
//default should be POST. Hell, you should never really be using GET for this..
//also, the default submit value is Submit
$this->formMethod = isset($args['formMethod']) ? $args['formMethod'] : "POST";
$this->submitBtnVal = isset($args['submitBtnVal']) ? $args['submitBtnVal'] : "Submit";
}
//get functions
function getFormName () { return $this->formName; }
function getFormAction () { return $this->formAction; }
function getFormMethod () { return $this->formMethod; }
function getSubmitBtnVal () { return $this->submitBtnVal; }
function getEncType () { return $this->encType; }
//set functions
function setFormName ($newName) { $this->fromName = $newName; }
function setFormAction ($newAction) { $this->formAction = $newAction; }
function setFormMethod ($newMethod) { $this->formMethod = $newMethod; }
function setEncType ($newEType) { $this->encType = $newEType; }
function addTag($newTag) {
if ($newTag instanceof formTag || $newTag instanceof fieldSetCont || $newTag instanceof newLine
|| $newTag instanceof noteTag)
$this->formObjArray[] = $newTag;
else throw new Exception ("You did not add a compatible tag.");
}
I'd like to be able to call $myForm->getTagByName("nameA")->setRequired(true);
How would I do that? Or would I need to do something more like..
$tagID = $myForm->getTagByName("nameA");
$myForm->tagArray(tagID)->setRequired(true);
Nothing in your code seems to be protected so you should have no trouble accessing any of it.
It looks like all your tags are in $formObjArray so it should be trivial to filter than array and return tags that match the name you've passed in. The trouble you will have is that, getTagByName really should be getTagsByName and should return an array because you can have more than one tag with the same name. Since it will return an array, you can not call setRequired on the return value, arrays don't have such a method. You'll need to do it more like:
$tags = $myForm->getTagsByName("nameA");
foreach ($tags as $tag) {
$tag->setRequired(true);
}
Exactly what are you stuck on? Maybe I don't understand the question very well.
So maybe the filtering has you stuck? Try this (if you you're using at least php 5.3)
function getTagsByName($tagname)
{
return array_filter($this->formObjArray, function($tag) use($tagname) {
return $tag->getName() == $tagname;
});
}
No ifs or switches.
Prior to 5.3, you don't have lambda functions so you need to do it differently. There are several options but this may be the simplest to understand:
function getTagsByName($tagname)
{
$out = array();
foreach ($this->formObjArray as &$tag) {
if ($tag->getName() == $tagname) {
$out[] = $tag;
}
}
return $out;
}
In your addTag method, you are storing new tags in $this->formObjArray using the [] notation, which will just append the new tag to the end of the array. If your tag objects all have a getName() method, then you can do something like this:
$this->formObjArray[$newTag->getName()] = $newTag;
Then, you can easily add a getTagByName() method:
public function getTagByName($name) {
if (array_key_exists($name, $this->formObjArray) {
return $this->formObjArray($name);
}
else {
return null;
}
}
Please beware of the solutions suggesting you to iterate through all the tags in your array! This could become very costly as your form gets larger.
If you need to use the [] construct because the order of the elements added is important, then you can still maintain a separate index by name, $this->tagIndex, that will be an associative array of name => tag. Since you are storing object references, they will not be using much space. Assuming that getTagByName will be used many times, this will save you a lot of resources over iterating the tags array on every call to getTagByName.
In that case, your addTag method would look like this:
$this->formObjArray[] = $newTag;
$this->tagIndex[$newTag->getName()] = $newTag; // it seems that you're doubling the memory needed, but you're only storing object references so this is safe
EDIT : Here is some modified code to account for the fact that multiple tags can have the same name:
In your addTag() method, do:
$this->formObjArray[] = $newTag;
$tag_name = $newTag->getName();
if (!array_key_exists($tag_name, $this->tagIndex)) {
$this->tagIndex[$tag_name] = array();
}
$this->tagIndex[$tag_name][] = $newTag
You can then rename getTagByName to getTagsByName and get the expected result.
As mentioned in the comments, this is only useful if you will call getTagsByName multiple times. You are trading a little additional memory usage in order to get quicker lookups by name.
I'm learning Yii Framework . I'm working with a framework first time, i need some advices.
I have a getSocials() function on my Controller .
private function getSocials($id)
{
$socials=Socials::model()->find("socials_user=$id");
foreach ($socials as $social)
{
$type = $social["socials_type"];
$allSocial .= "<li>$type</li>";
}
return $allSocial;
}
(it's private because i'm calling it from another function only).
I'll explain it line by line,
$socials=Socials::model()->find("socials_user=$id");
Getting datas from database which socials_user collumn equals to $id, via Socials model.
foreach ($socials as $social)
$socials returning as an array because there are a few lines which socials_user collumn equals to $id on database .
$allSocial .= "<li>$type</li>";
On foreach loop, adding <li>...</li> to end of string, so $allSocial will be <li>...</li><li>...</li>...
BUt i'm getting Undefined variable: allSocial error . When i remove dot from front of equal symbol (=), it's working. But this time on foreach loop, it's overwriting always and finally $allSocial containing only last <li>...</li>
Are there any logical mistake ?
$allSocial is not defined anywhere, you cant attach a string to an undefined variable. Try it like this:
private function getSocials($id)
{
$socials=Socials::model()->find("socials_user=$id");
$allSocial = '';
foreach ($socials as $social)
{
$type = $social["socials_type"];
$allSocial .= "<li>$type</li>";
}
return $allSocial;
}
You need to define $allSocial before you try to concatenate anything to it. You may also want to consider returning an array instead so you can easily access the different strings.
private function getSocials($id) {
$socials=Socials::model()->find("socials_user=$id");
$allSocial = array();
foreach ($socials as $social)
{
$type = $social["socials_type"];
$str = "<li>$type</li>";
array_push($allSocial, $str);
}
return $allSocial;
}
find function will return only one record which is not an array so foreach will never execute
replace the code with following to get it working right :
private function getSocials($id)
{
$socials=Socials::model()->findAll('socials_user=:socials_user',
array(':socials_user'=>1));
$allSocial = '';
foreach ($socials as $social)
{
$type = $social["socials_type"];
$allSocial .= "<li>$type</li>";
}
return $allSocial;
}
Ok, so I have a class and I would like to be able to get any trackName (two dimensional array) after initializing an object in another php script. This is a part of the class that is relevant:
class fetchData{
public $artistName;
public $trackName;
public function getArtistTracks(){
$i = 0;
if( $tracks = getTracks() ){
foreach ( $tracks['results'] as $track ){
// $artistName is an array of strings (defined as public)
$name[$this->artistName][$i] = $track['name'];
$i++;
}
}
return $name;
}
// later in the class one other function there is this
function initialize(){
...
...
$this->trackName = $this->getArtistTracks();
}
}
Here is how I thought I could call artistName and trackName from another script:
$temp = new fetchData();
echo $temp->artistName[3]; // this works (returns 'some_artist_name' for example)
echo $temp->trackName[$temp->artistName[3]][1]; // this doesn't work
echo $temp->trackName['some_artist_name'][1]; // this also doesn't work
I tried a few other ways. For example instead of this:
$name[$this->artistName][$i] = $track['name'];
I would put this:
$this->name[$this->artistName][$i] = $track['name'];
without the return in getArtistTracks() and without the line in initialize() but that didn't work also. how can I get these trackNames from within another script?
thank you =)
to close this one up, the function should look like this ($i was in the wrong loop):
public function getArtistTracks(){
if( $tracks = getTracks() ){
$i = 0;
foreach ( $tracks['results'] as $track ){
// $artistName is an array of strings (defined as public)
$name[$this->artistName][$i] = $track['name'];
$i++;
}
}
return $name;
}
$name[$this->artistName ---> [$i] <--- ] = $track['name'];
of course, only if $temp->artistName; is array.