PHP manipulating multiarray data - multidimensional-array

I have a problem. I don't know how to show the exactly data I want.
My array is like this:
$races[$numRace][$finalPosition]
$races[1][1] = array ('stephan','1:27,895');
$races[1][2] = array ('george', '1:29,075');
$races[1][3] = array ('peter', '1:29,664');
$races[1][4] = array ('benson', '1:29,915');
$races[2][1] = array ('benson', '1:41,113');
$races[2][2] = array ('stephan','1:41,434');
$races[2][3] = array ('george', '1:43,654');
foreach ($races as $v1) {
foreach ($v1 as $v2) {
foreach ($v2 as $v3) {
echo "$v3\n";
}
}
}
This one shows me every data of $race array.
My question is: How can I do for showing just results for race 2?
Important: We don't know how many runners have participated on each race (So, we need a "foreach").
I would like a result like this:
benson
stephan
george

Simply iterate through only the relevant array. Based on your code your foreach should be:
foreach ($races[2] as $pos => $info){
echo $pos.': '.$info[0];
}
I've hard-coded the value 2 in the code but you could easily use a variable (foreach ($races[$raceNum]).
If you don't already know, => makes it possible for us to use both the key and the value as variables in our loop.

Related

get count with hasMany not working yii2

I have CLub model (clubs) hasMany with User model like
Club n-n User
and I have UserClub model with columns: id, club_id, user_id, etc
In Club model
public function getCountUsers()
{
return $this->hasMany(UserClub::className(), ['club_id'=>'id'])->count();
}
I wanna count all User on Club as code:
$query = Club::find()
->joinWith(['countUsers']);
// ->with('countUsers');
->all();
so it is not working and throwing an error
Club has no relation named \"countUsers\"."
Because it isn't a relation as it does not return a model object or an array of model objects, instead you are using ->count() that makes it return a string that contains the total count for the user against the club.
If you are looking to get a count for the users against all the Clubs you can use the currently defined relation like $club->countUser see below.
$clubs=Club::find()->all();
foreach($clubs as $club){
echo $club->countUser;
}
or change the relation to
public function getCountUser(){
return $this->hasMany(UserClub::className(), ['club_id'=>'id']);
}
and use it like
$clubs=Club::find()->all();
foreach($clubs as $club){
echo count($club->countUser);
}
or like below
$clubs=Club::find()->all();
foreach($clubs as $club){
echo $club->getCountUser()->count();
}
EDIT
You are actually trying to transform the following query using ActiveRecord as far as I understood from the discussion.
SELECT clubs.id, count(user_clubs.id) as total
FROM
clubs
left join user_clubs on clubs.id = user_clubs.club_id
group by clubs.id
if that is correct you can use the following
Clubs::find ()
->alias ( 'c' )
->select ( [ new \yii\db\Expression ( 'c.[[id]], count(uc.[[id]]) as total' ) ] )
->leftJoin ( '{{%user_clubs}} uc' , 'uc.club_id=c.id' )
->groupBy ( 'c.id' )
->all ();
Note : You have to do one more thing you have to add a public property $total inside your Club model and add it to safe rules, because you are selecting the count as an alias total and until unless you define it inside the model the result set won't show you the count, so add the following inside the Club model.
public $total;
under rules
[[other fields...,'total'] , 'safe' ] ,
EDIT2
For some reason, I have a feeling that you are trying to count by specifying a relation instead of specifying the ->leftJoin () with the table user_clubs in the query.
If that is so then you have to change your relation getUserCount() you should better give a meaningful name that describes it. i would rename it to getClubUsers()
public function getClubUsers(){
return $this->hasMany(UserClub::className(), ['club_id'=>'id']);
}
After this, you still have to declare a public property $total as I described before inside your Club model, and add it to safe rules.
Now you can write your query in the following way
Clubs::find ()
->alias ( 'c' )
->select ( [ new \yii\db\Expression ( 'c.[[id]], count(cu.[[id]]) as total' ) ] )
->joinWith( ['clubUsers cu'] )
->groupBy ( 'c.id' )
->all ();
You can do this with join, in my case i get users who have more than 0 referrals.
$users = User::find()->with('referrals')
->from(User::tableName() . ' t')
->join('left join',User::tableName().' r','r.Deeplink = t.ReferralID')
->select('t.*,count(r.ID) as ct')
->groupBy('t.ID')
->andFilterHaving(['>','ct',0])
->all();
Hi your relation is correct check you error Club has no relation named \"countUsers\"."
Means you are calling a relation which not exist :
change query like this, Relation name should be in Club Model
public function getCount(){
return $this->hasMany(UserClub::className(), ['club_id'=>'id']);
}
$clubs=Club::find()->all();
foreach($clubs as $club){
echo count($club->getCount);
}
$query = Club::find()
->joinWith(['count']);
// ->with('countusers');
->all();
If you want count just do like this .
Load the Club model .
$club_model = Club::find()
$count = club_model->count;

Doctrine ORM many-to-many find all by taglist

I'v got simple m2m relation (book -> book_mark <- mark). I want to find item(book) by 1-2-3... x-count of tags(marks). Example: Book1 got these tags: [Mark1, Mark2, Mark3], Book2 got these tags: [Mark1, Mark3, Mark4]. Search list is [Mark1, Mark2]. I want to find only items, which have ALL tags from Search list, i.e. only Book1 in this example.
I have tried many ways and spend much time google it, but didn't find the answer.
Closest that I have is this:
return $this->createQueryBuilder('b')
->select('b, m')
->leftJoin('b.marks_list', 'm')
->andWhere(':marks_list MEMBER OF b.marks_list')
->setParameter('marks_list', $marksList)
->getQuery()->getArrayResult();
But it's looking for books which have at least 1of the parameters, not all of them together
Next, I'v decided that I'm absolutely wrong and start thinking this way:
public function findAllByMarksList(array $marksList)
{
$qb = $this->createQueryBuilder('b')
->select('b, m')
->leftJoin('b.marks_list', 'm');
for ($i = 0; $i<count($marksList); $i++){
$qb->andWhere('m.id in (:mark'.$i.')')
->setParameter('mark'.$i, $marksList[$i]);
}
return $qb->getQuery()->getArrayResult();
}
But here I faced another problem: This code is checking only 1 mark and then always returns an empty set if the number of parameters is more than 1.
Best regards.
So, updated answer... It works (I have relation many to many between reviews and brands) it's the same situation, but for example if you have
Book 1 - mark1, mark2, mark3
Book 2 - mark1, mark2, mark3, mark4
with this code you will also find the book2, because all of it marks are in this list.
If you need to find book which haves only these 3 tags, you additionally need to add checking for count. (Count of tags = count of tagList)
public function test()
{
// just selecting for list for test
$brandsList = $this->_em->createQueryBuilder()
->select('b')
->from('ReviewsAdminBundle:Brands', 'b')
->where('b.id in (:brandIds)')
->setParameter('brandIds', [6,4])
->getQuery()
->getResult();
dump($brandsList);
// query part
$qb = $this->createQueryBuilder('r')
->select('r')
->leftJoin('r.brand', 'brands')
->where('r.published = 1');
foreach ($brandsList as $oneBrand) {
/** #var Brands $oneBrand */
$identifier = $oneBrand->getId();
$qb->andWhere(':brand'.$identifier.' MEMBER OF r.brand')
->setParameter('brand'.$identifier, $identifier);
}
dump($qb->getQuery()->getResult());
die;
}
ps. Additionally you can check doctrine2 queryBuilder must return only result matching with array values (ids): 0/Null and/or One and/or Many id(s) have to return One result (close to our situation)
And, I think there's not better way of accomplishing this. Either you use multiple andWheres to compare id OR use MEMBER OF

Combining a string and a variable value to access an existing variable

Imagine I have the following set of defined variables:
$sportmenu_1: #23765c;
$sportmenu_3: #5e6b34;
$sportmenu_4: #7d7e6c;
$sportmenu_6: #786857;
$sportmenu_8: #487a91;
I also have a list containing the "id" or the last digit of each variable as:
$list: 1 3 4 6 8;
I then want to the $sportmenu_ variables to both name the css selectors and populate the properties, I'm using a list and a foreach as follows:
#each $id in $list_id_sports {
#sportmenu_#{$id} { //this works fine
.menu-sport-item {
background-color: #{$sportmenu_}#{$id}; //here's the issue!
}
}
}
The problem is that I cannot find a way to combine a string and the $id from the foreach to generate a variable that the Sass compiler will understand. Basically, I want the foreach to create a new variable by combining $sportmenu_ and the value of $id. Not sure if this is possible.
My solution doesn't work, since $sportmenu_ doesn't exist. I've tried combining a string and the $id as: "$sportmenu_"#{$id} but this just creates a string followed by the value of $id.
Thanks!
Why can't you do something like this? Using maps
$list: (1: #23765c, 3: #5e6b34, 4: #7d7e6c, 6: #786857, 8: #487a91);
//$id grabs your map index, and $val grabs your hex color values
#each $id, $val in $list {
#sportmenu_#{$id} {
.menu-sport-item {
background-color: #{$val};
}
}
}
You can try it out on SassMeister. Which outputs :
#sportmenu_1 .menu-sport-item {
background-color: #23765c;
}
.....
All I am doing over here is nothing but using maps(kind of hash), looping over, and printing colors accordingly.
Also, what you were trying won't work. You are trying to interpolate two variables and trying to create a dynamic variable name on compile.
#{$sportmenu_}#{$id}; //will throw undefined $sprotsmenu_ error

Smarty Math Function Foreach Loop

I am using smarty templating engine and am encountering a math issue. I am trying to create a total amount (sum) based on amounts in the array. (Normally I would do this at the server level, but do to the way that I create the array, dont think that is possible.) I am merging two arrays into one, but each array shares an 'Amount' which I am trying to determine the 'Total Amount'
Here are the steps I am taking two arrays pushing into one array:
foreach ($data_main1 as $transaction_main1) {
$json_decoded = json_decode($transaction_main1['NewObject']);
$amount = $transaction_main1['Amount'];
$mycart1[] = array('ParentType' => $ParentType, 'Amount' => $amount);
}
$mycart2=array();
foreach ($data_main2 as $transaction_main2) {
$json_decoded = json_decode($transaction_main2['NewObject']);
$amount = $transaction_main2['Amount'];
$mycart2[] = array('ParentType' => $ParentType, 'Amount' => $amount);
}
$mycart = array_merge((array)$mycart1, (array)$mycart2);
$smarty->assign('cart', $mycart);
Here is my Smarty along with the math equation that does not show the value:
{assign var=last value=$cart[cart].Amount+1}
(I am certainly open to the idea of creating a total amount on the array_merge, just unsure how to do that, or even if it is possible)
Do you know about the {math} Smarty bult-in function?
{math equation="x + 1" x=$cart[cart].Amount}
Let me know if it works.

Faster and less cheesy matching of items from 2 collections

Hi I need to iterate two collections containing different object types and do some matching, adding matched items to a 3rd list.
private CheesyMatch( BindingList< MyTypeA > theListA, BindingList< MyTypeB > theListB )
{
foreach( MyTypeA item in theListA )
{
foreach( MyTypeB item2 in theListB )
{
if( item.name == item2.name )
{
item.matched = true;
item2.matched = true;
MyMatchedList.items.add( new matchedItem( item, item2 ) );
}
}
}
}
Is there a better/more efficient way to do this? (I have simplified things a little, as I have some code in my code that copies to new local collections before iterating them, as I was having threading issues.
Not sure what language this is, but there must be some method liked "exists" or "contains" where you do two loops in series. In pseudo code
foreach item in ListA
if ListB.exists(item) then
MatchedList.items.add(item)
end if
endfor
foreach item in ListB
if ListA.exists(item) then
MatchedList.items.add(item)
end if
endfor
That way you only go over each collection once rather than doing ListB N times where ListA has N items. Does this make sense?

Resources