1. Advertising
    y u no do it?

    Advertising (learn more)

    Advertise virtually anything here, with CPM banner ads, CPM email ads and CPC contextual links. You can target relevant areas of the site and show ads based on geographical location of the user if you wish.

    Starts at just $1 per CPM or $0.10 per CPC.

Array Loops

Discussion in 'PHP' started by Jeremy Benson, Jan 7, 2017.

  1. #1
    Hey,

    I'm looking for the best way to loop over an array for matches, and non matches. Basically I want to output a tag html for when there is a tag match, and a different html for when there isn't a match. The code has to support both arrays having a different amount of data.

    Thanks for reading.

    $stmGenres = $db->prepare('SELECT `tag` FROM `tags` WHERE `username` = ? AND `category` = ?');
                   $stmGenres->execute(array($poster->return_username(), 'genres'));
                   $posterGenres = $stmGenres->fetchAll();
                  
                   $stmUserGenres = $db->prepare('SELECT `tag` FROM `tags` WHERE `username` = ? AND `category` = ?');
                   $stmUserGenres->execute(array($poster->return_username(), 'genres'));
                   $userGenres = $stmUserGenres->fetchAll();
                  
                   if(count($posterGenres) >= 1)
                   {
                      
                       echo '<div id="browse-search-tray" class="buffer-top">
                            <h4 class="sm-buffer-bottom">Genres</h4>';
                      
                        foreach($posterGenres as $key => $val)
                            {
                                           
                                foreach($userGenres as $key2 => $val2)
                                {
                                   
                                    if($posterGenres[$key]['tag'] == $userGenres[$key2]['tag'])
                                    {
                                        // match
                                        echo '<span class="label label-default tagselected" style="margin-bottom:4px;">'.$posterGenres[$key]['tag'].'</span>';
                                       
                                       
                                    }else{
                                        // no match
                                       
                                        echo '<span class="label label-default tag" style="margin-bottom:4px;">'.$posterGenres[$key]['tag'].'</span>';
                                       
                                    }
                                   
                                }
                                               
                            }
                      
                       echo '</div>';
                      
                   }
    Code (markup):

    SEMrush
     
    Jeremy Benson, Jan 7, 2017 IP
    SEMrush
  2. ThePHPMaster

    ThePHPMaster Well-Known Member

    Messages:
    715
    Likes Received:
    49
    Best Answers:
    31
    Trophy Points:
    125
    #2
    Unless I am reading this wrong $posterGenres is the same as $userGenres. Both queries are the same and will result in the same array.

    Besides that you can speed things up by having an array of user genres : userGenres = array(1 => true, 2 => true, etc..); and doing and isset check when looping through posterGenres. This will save you the looping.
     
    ThePHPMaster, Jan 7, 2017 IP
  3. sarahk

    sarahk iTamer Staff

    Messages:
    22,930
    Likes Received:
    3,088
    Best Answers:
    77
    Trophy Points:
    615
    #3
    or even an array_key_exists or in_array.

    I suspect the usernames are meant to be looking at the author of an article and the logged in user (normally different).
     
    sarahk, Jan 7, 2017 IP
  4. Jeremy Benson

    Jeremy Benson Member

    Messages:
    322
    Likes Received:
    4
    Best Answers:
    0
    Trophy Points:
    48
    #4
    Yes, sorry, I didn't notice that typo. Those are supposed to be two different user objects. I'll fix that and see how it's running :p
     
    Jeremy Benson, Jan 10, 2017 IP
  5. Jeremy Benson

    Jeremy Benson Member

    Messages:
    322
    Likes Received:
    4
    Best Answers:
    0
    Trophy Points:
    48
    #5
    array_key_exists won't work because of multidimensional arrays. I fixed the code above. In the select it's just $poster->return_username() and $user->return_username()

    It's outputting to many tags because of the double foreach loops.
     
    Jeremy Benson, Jan 11, 2017 IP
  6. sarahk

    sarahk iTamer Staff

    Messages:
    22,930
    Likes Received:
    3,088
    Best Answers:
    77
    Trophy Points:
    615
    #6
    Because you're learning as you go I'd tend to break this down to steps.
    1. get your data
    2. process your data
    3. output your data
    so, without testing, I'd probably start with this

    <?php
    $stmGenres = $db->prepare('SELECT `tag` FROM `tags` WHERE `username` = ? AND `category` = ?');
    $stmGenres->execute(array($poster->return_username(), 'genres'));
    $posterGenres = $stmGenres->fetchAll();
    
    $stmUserGenres = $db->prepare('SELECT `tag` FROM `tags` WHERE `username` = ? AND `category` = ?');
    $stmUserGenres->execute(array($user->return_username(), 'genres'));
    $userGenres = $stmUserGenres->fetchAll();
    
    $matches = array();
    
    if (count($posterGenres) > 0) {
    
        foreach ($posterGenres as $key => $val) {
            $tag = $posterGenres[$key]['tag'];
    
            foreach ($userGenres as $key2 => $val2) {
                if ($tag == $userGenres[$key2]['tag']) {
                    // even if it's in the array there's no harm in overwriting the value
                    $matches[$tag] = 'tagselected';
                } else {
                    // just in case a tag can turn up twice, take the check out if that's not possible
                    if (!array_key_exists($tag, $matches)) {
                        $matches[$tag] = 'tag';
                    }
                }
            }
        }
    }
    
    // now that we have our tags all sorted out we can output them to the browser
    if (count($matches) > 0) {
        echo '<div id="browse-search-tray" class="buffer-top">
     <h4 class="sm-buffer-bottom">Genres</h4>';
    
        foreach ($matches as $tag => $class) {
            echo "<span class='label label-default {$class}' style='margin-bottom:4px;'>{$tag}</span>";
        }
        echo '</div>';
    }
    Code (markup):
     
    sarahk, Jan 11, 2017 IP
  7. Jeremy Benson

    Jeremy Benson Member

    Messages:
    322
    Likes Received:
    4
    Best Answers:
    0
    Trophy Points:
    48
    #7
    Thanks Sarah :) Code is brilliant, and I'm no longer fetched up. Thanks again :p
     
    Jeremy Benson, Jan 12, 2017 IP
  8. deathshadow

    deathshadow Illustrious Member

    Messages:
    8,269
    Likes Received:
    1,452
    Best Answers:
    219
    Trophy Points:
    465
    #8
    span class="label

    if it's a label why isn't it a label tag? Lemme guess, bootcrap or something similar?

    You only select TAG, so why are you wasting time returning an index and accessing the array by index?!?

    There is no reason to waste time counting ASSUMING those are two different query (they aren't right now as @ThePHPMaster pointed out), the rest of it could simply be:

    
    // again, why the hell are these two the same query?!?
    // taking a WILD guess as to what it should be
    
    $stmt = $db->prepare('
    	SELECT tag
    	FROM tags
    	WHERE username = ?
    ');
    $stmt->execute([$poster->return_username()]);
    $userKeys = $stmt->fetchAll();
    
    $stmt = $db->prepare('
    	SELECT tag
    	FROM tags
    	WHERE category = ?
    ');
    $stmt->execute(['genres']);
    $genreKeys = $stmt->fetchAll();
    
    $result = array_merge(
    	array_fill_keys($userKeys, 'tag'),
    	array_fill_keys($genreKeys, 'tag'),
    	array_fill_keys(
    		array_intersect($userKeys, $genreKeys),
    		'tagCategory'
    	)
    );
    
    if (count($result)) {
    
    	echo '
    		<div id="browse-search-tray">
    			<h2>Genres</h2>';
    			
    	foreach ($result as $tagName => $className) echo '
    			<span class="', $className, '">', $tagName, '</span>';
    			
    	echo '
    		</div>';
    		
    }
    
    Code (markup):
    Though a bit wasteful of memory, it's a lot simpler -- I'm assuming your logic is you want ALL tags if the category matches OR the user matches, not BOTH, but if they exist in both give it a different class?

    You get a list of those that match your desired genre, a list of the tags for the user, you merge the two into an associative array keyed by tag, then merge and intersection of the two with the higher priority class. When using array_merge the latter array parameter will overwrite an existing index in the associative result.

    So lets say for user you had:

    red, blue, green, yellow

    ... and for genre you had:
    blue, yellow, orange, purple

    The result of that array merge and intersect should be:

    
    [
      'red' => 'cat',
      'blue' => 'catselected',
      'green' => cat',
      'yellow' => 'catselected',
      'orange' => 'cat',
      'purple' => 'cat'
    ]
    
    Code (markup):
    Otherwise what you are doing makes no sense whatsoever... or do you only want the ones in user that if the genre tag exists select them... It's REALLY unclear what your data is and what you're trying to do with it.
     
    deathshadow, Jan 18, 2017 IP