1

In my website, users can publish their profile in different languages, something like LinkedIn, now we're searching between firstname of users, for example we search for: 'ar' and we look into all profiles languages, we will have an array in return like:

array
  0 => string '20=>en' (length=5)
  1 => string '42=>en' (length=5)
  2 => string '20=>fa' (length=5)
  3 => string '42=>sp' (length=5)
  4 => string '12=>fr' (length=5)
  5 => string '83=>ar' (length=5)
  6 => string '160=>sp' (length=5)

The above array shows that we've got 6 profiles which matches our search 'ar' in different languages, the above array says:

0 => Match found for User with ID = 20 in English Lang(en) profile
1 => Match found for User with ID = 42 in English Lang(en) profile
2 => Match found for User with ID = 20 in Farsi Lang(fa) profile
3 => Match found for User with ID = 42 in Spanish Lang(sp) profile
4 => Match found for User with ID = 12 in French Lang(fr) profile
5 => Match found for User with ID = 83 in Arabic Lang(ar) profile
6 => Match found for User with ID = 160 in Spanish Lang(sp) profile

Now, we want to show the results, but as a matter of fact, as you see in the results, we've got matches for 'ar' for the user with ID = 20 in Both English and Farsi languages, but we can't show 2 results of the same person! so we need to let go of the axillary results, so the array above should be filtered and uniqued based by user IDs and priority of the languages, my priority for the languages is:

  1. $_SESSION['my_lang'];
  2. English Language (en);
  3. Rand();

The person who enters 'ar' as his search query has a $_SESSION['my_lang'], so in the results array for the user which has results in $_SESSION['my_lang'] we should keep that results and let go of the other matches for the same person.

After $_SESSION['my_lang'], our priority should be EN lang, if a person has results in N languages, but we could not found the match in $_SESSION['my_lang'], then we should keep the results in en lang and clear the rest of results for that person.

after the above priorities, actually nothing matters, we just need to keep one of the results for that person and get rid of other results for that person, so the languages should be selected randomly...

I have no idea how this could be accomplished, I would appreciate any kind of help.


In my example, I have an array like:

array
  0 => string '20=>en' (length=5)
  1 => string '42=>en' (length=5)
  2 => string '20=>fa' (length=5)
  3 => string '42=>sp' (length=5)
  4 => string '12=>fr' (length=5)
  5 => string '83=>ar' (length=5)
  6 => string '160=>sp' (length=5)

but in your example, you have an array like:

$users = array(
  array('id'=> 20, 'lang'=>'en'),
  array('id'=> 42, 'lang'=>'en'),
  array('id'=> 20, 'lang'=>'fa'),
  array('id'=> 42, 'lang'=>'sp'),
  array('id'=> 12, 'lang'=>'fr'),
  array('id'=> 83, 'lang'=>'ar'),
  array('id'=> 160, 'lang'=>'sp'));

How should I make my array to look like your array, so your codes work..? Thanks

2
  • 2
    It sounds like you might want to include this limitation/ordering in whatever is performing the search query and not on the returned array of data. Commented Jan 2, 2013 at 21:05
  • @MattRazza The search query is really really complicated, I just figured that out with many joins and filtering... I prefer to limit the results, any idea? Commented Jan 2, 2013 at 21:10

1 Answer 1

1

There are probably better (more efficient) ways to do this, but here is one way. Doing it in 3 steps. (1) Create a language array, (2) order the user array, based off the language array, (3) make the User array have unique users.

note Step 2 utilizes anonymous functions, so if PHP v < 5.3, use second Step 2 example

Array of Users

$users = array(
               array('id'=> 20, 'lang'=>'en'),
               array('id'=> 42, 'lang'=>'en'),
               array('id'=> 20, 'lang'=>'fa'),
               array('id'=> 42, 'lang'=>'sp'),
               array('id'=> 12, 'lang'=>'fr'),
               array('id'=> 83, 'lang'=>'ar'),
               array('id'=> 160, 'lang'=>'sp'));

Step 1

//Create an Array of Languages
$langs[0] = $_SESSION['my_lang']; // Set $_SESSION['my_lang'] as 1st
if($langs[0] != 'en'){
    $langs[1] = 'en';} // Set en as 2nd, if not already as 1st

//Add remainder of User languages to Languages
shuffle($users);  // This randomizes the $user array so the rest of the languages are random. Can be removed if randomizing the rest of the languages is not necessary.
foreach ($array as $lang) {
    if(!in_array($lang['lang'],$langs))
        $langs[] =$lang['lang'];
}

Step 2 use with php v >= 5.3 - uses anonymous functions

//Reorder the User array, bases off Language array
$keys = array_flip($langs);
usort($users, function($a, $b) use($keys)
{
    return $keys[$a['lang']] - $keys[$b['lang']];
});

Step 2 use with php v < 5.3

//Reorder the User array, bases off Language array
$keys = array_flip($langs);
function custom($a,$b){
   global $keys;
   return $keys[$a['lang']] - $keys[$b['lang']];
}
usort($users, "custom");

Step 3

//Make the User array unique
$temp_array = array();
foreach ($users as &$v) {
    if (!isset($temp_array[$v['id']]))
        $temp_array[$v['id']] =&$v;
}
$users = array_values($temp_array);

phpFiddle w/ Step 2 for php v >= 5.3 - http://phpfiddle.org/main/code/xva-dzn

phpFiddle w/ Step 2 for php v < 5.3 - http://phpfiddle.org/main/code/p02-r6b


Edit
Assuming that your array -

array
  0 => string '20=>en' (length=5)
  1 => string '42=>en' (length=5)
  2 => string '20=>fa' (length=5)
  3 => string '42=>sp' (length=5)
  4 => string '12=>fr' (length=5)
  5 => string '83=>ar' (length=5)
  6 => string '160=>sp' (length=5)

is a var_dump() of something like this-

$returned = array(
  0 => '20=>en',
  1 => '42=>en',
  2 => '20=>fa',
  3 => '42=>sp',
  4 => '12=>fr',
  5 => '83=>ar',
  6 => '160=>sp');

Using explode() and a for() loop you change the array into a multi demintional array to be used in the above steps.

$users = array();
for($i=0;$i<count($returned);$i++){
     $split_returned = explode("=>",$returned[$i]); // split up each line at the '=>'
     $users[$i]['id'] = $split_returned[0];   // set the 'id'
     $users[$i]['lang'] = $split_returned[1];}  // set the 'lang'
Sign up to request clarification or add additional context in comments.

5 Comments

Excellent Answer! is this going to use much CPU/Ram!? any ideas for more efficient ways to do this?
Unfortunately, I can't help much with CPU/Ram benchmarking, as I am not well versed in that. I ran it 3 times with the current array and the run time was fairly small - 0.000227928161621 / 0.000319004058838 / 0.000295877456665, but I don't know what effect it would have on CPU/Ram usage, as well as how it would change with larger arrays. Also, in regards to more efficient ways to accomplish this. My only other suggestion is to find a way to add it to your query, but as you mentioned in a comment above your query is already complex. So I am not sure of any other options.
I assume that your array is a var_dump() of your actual array. If so, I have posted an edit to my question, showing how to change your array using explode() and a for() loop.
Sorry for bothering again, but my server PHP version seems to not support Step 2, is there any other ways to do the Step 2 in PHP < 5.3, thanks a lot
I have updated Step 2 and added how to do it with php v < 5.3 & added a phpFiddle link next to the original phpFiddle link

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.