-1

Rearrange words in Array based on position of the first array. In my code there are two array my first array is the base array from which i am going to compare it with second array and make the position same as first array.

Consider 2 input by considering 1 input as base i am applying levenshtein(metaphone(each word database),metaphone(each word of bank)) then based on that arranging the words of bankdata in new array

databaseName = LAL BAHADUR SHASTRI bankdata = SHASTRI LAL source code will only rearrange bankdata and stored in in new array current output of bankdata : LAL SHASTRI

Rearrangement is happening properly just need to arrange words in array

        $db = 'LAL BAHADUR SHASTRI YADAV';
        $bank = 'SHASTRI LAL';
        $a = reArrangeArray($db,$bank);

        function reArrangeArray($db,$bank)
        {
            $dataBaseName = $db;
            $bankdataRows = [$db,$bank,];
            $dbWords = preg_split("#[\s]+#", $dataBaseName);     
            foreach ($bankdataRows as $bankdata)
            {
            $bankWords = preg_split("#[\s]+#", trim($bankdata));
            $result    = [];    
            if(!empty($bankWords))
                foreach ($dbWords as $dbWord)
                {
                $idx   = null;
                $least = PHP_INT_MAX;
                foreach ($bankWords as $k => $bankWord)
                    if (($lv = levenshtein(metaphone($bankWord),metaphone($dbWord))) < $least)
                    {
                    $least = $lv;
                    $idx   = $k;
                    }
                @$result[] = $bankWords[$idx];
                unset($bankWords[$idx]);
                }
            $result = array_merge($result, $bankWords);
            var_dump($result);
            }
        }

Case 1: CURRENT OUTPUT

        array (size=4)
        0 => string 'LAL' (length=3)
        1 => string 'BAHADUR' (length=7)
        2 => string 'SHASTRI' (length=7)
        3 => string 'YADAV' (length=5)

        array (size=4)
        0 => string 'LAL' (length=3)
        1 => string 'SHASTRI' (length=7)
        2 => null
        3 => null

Expected Output

I need array position as same as databaseArray

        $dbName = 'LAL BAHADUR SHASTRI YADAV';
        $bankName = 'SHASTRI LAL';

        array of db (size=4)
        0 => string 'LAL' (length=3)
        1 => string 'BAHADUR' (length=7)
        2 => string 'SHASTRI' (length=7)
        3 => string 'YADAV' (length=5)

        array of bankname (size=4)
        0 => string 'LAL' (length=3)
        1 => #
        2 => string 'SHASTRI' (length=7)
        3 => ###

if word not found in first array it should be place with # since position is 3 which dont have matching element it has 3 #

        array (size=4)
        0 => string 'LAL' (length=3)
        1 => string 'BAHADUR' (length=7)
        2 => string 'SHASTRI' (length=7)
        3 => string 'YADAV' (length=5)

        array (size=4)
        0 => string 'LAL' (length=3)
        1 => string 'SHASTRI' (length=7)
        2 => null
        3 => null

Expected Output

I need array position as same as databaseArray

        $dbName = 'LAL BAHADUR SHASTRI YADAV';
        $bankName = 'SHARI LAL';

        array of db (size=4)
        0 => string 'LAL' (length=3)
        1 => string 'BAHADUR' (length=7)
        2 => string 'SHASTRI' (length=7)
        3 => string 'YADAV' (length=5)

        array of bankname (size=4)
        0 => string 'LAL' (length=3)
        1 => #
        2 => string 'SHARI' (length=7)
        3 => ###

This case would be calculated based on levenshtein(metaphone($bankWord),metaphone($dbWord))

Case 2

Input :

$dbName = NikithaRani MohanRao $bankdata = Nikitha Rani Mohan Rao

Output : $newbankdata = NikithaRani MohanRao

It should concatenate the word if found concatenated in $dbName

Note

Position of word is calculated just need to shift word in array by comparing first array

Expected Output

Problem Diagram

  • I'm not sure I understood - you want to rearrange the second array as the values in the first one? and fill the empty spot with `#` as the index? (not my down vote but the question is not so clear...) – dWinder Feb 01 '19 at 11:21
  • @dWinder yes i have added the expected output screenshot.yes you are right need to add # where word is not found –  Feb 01 '19 at 11:22
  • This start sound like matching problem. Maybe you should do it in brute force (`O(n*m^2)`) as calculate all option of levinstein distance and at each step take the minimum – dWinder Feb 02 '19 at 19:58
  • @dWinder Hope that can solve the issue because each calculation is important. The use of doing this is i need to match the score of two strings that is why the array position should match.How can we implement brute force `(O(n*m^2))` to your below source code –  Feb 03 '19 at 08:48
  • Edit my answer again with the brute-force code (not sure if there is any better way for your constrains...) – dWinder Feb 03 '19 at 09:14
  • 1
    @dWinder you made my day Legend Thanks –  Feb 03 '19 at 10:05

1 Answers1

1

I'm not sure I understand the entire question but let try to solve only the rearrange the array issue:

$a1 = explode(" ", "LAL BAHADUR SHASTRI YADAV");
// sort $a1 to whatever order you need
$a2 = explode(" ", "SHASTRI LAL");

foreach($a1 as $key => $e) { // for each element set him or fill with "#"
    $res[$key] = in_array($e, $a2) ? $e : str_repeat("#", $key); 
}

str-repeat is duplicate the char for x times. This code ran in O(n*m) - it can be modify to O(n) if needed (when n is the number of element in the first array).

I hope that helps and if not feel free to comment

Edited:

First define function for finding the Levenshtein minimum distance:

function foundLevenshteinMinIndex($word, $arr) {
    $word = metaphone($word);
    foreach ($arr as $k =>$e)
        $a[] = levenshtein($word,metaphone($e));
    return array_search(min($a), $a);
}

Now used the same $a1, $a2 as do:

foreach($a2 as $w) {
    $i = foundLevenshteinMinIndex($w, $a1);
    if (!isset($res[$i]) || (levenshtein(metaphone($a1[$i]), metaphone($res[$i])) > levenshtein(metaphone($a1[$i]), metaphone($w))))
        $res[$i] = $w;
}

for($i = 0; $i < count($a1); $i++) 
    if (!isset($res[$i])) // if not set in the index fill with "#'
        $res[$i] = str_repeat("#", $i);
// rearrange by int indexs
ksort($res);

Edited 2

Look at this implementation:

$a1 = explode(" ", 'LAL BAHADUR SHASTRI YADAV');
$a2 = explode(" ",'SHASTRI LAL NABA');

function getDist($a1, $a2) {
    foreach($a2 as $k1 => $w1)
        foreach($a1 as $k2 => $w2)
            $arr[$k1][$k2] = levenshtein(metaphone($w1), metaphone($w2));
    return $arr;
}

function getMin($arr) {
    $min = PHP_INT_MAX;
    $minX = $minY = null;
    foreach($arr as $x => $row)
        foreach($row as $y => $cell)
            if ($cell < $min) {
                $min = $cell;
                $minX = $x;
                $minY = $y;
            }
    return array($minX, $minY);
}

function removeIndex($arr, $x, $y) {
    unset($arr[$x]);
    foreach($arr as &$row)
        unset($row[$y]);
    return $arr;
}

$arr = getDist($a1, $a2);
while (count($arr) && count(reset($arr))) {
    list($x, $y) = getMin($arr);
    if (!isset($res[$y]))
        $res[$y] = $a2[$x];
    $arr = removeIndex($arr, $x, $y);
}

for($i = 0; $i < count($a1); $i++)
    if (!isset($res[$i])) // if not set in the index fill with "#'
        $res[$i] = str_repeat("#", $i);
ksort($res);

Notice this code has time complexity of O(n*(m^2)) when n is the first array and m is the second one

dWinder
  • 11,597
  • 3
  • 24
  • 39
  • thanks mate you have taken me close to the solution.But it should calculate the levenshtein(metaphone()) of both the words i.e $db = 'LAL BAHADUR SHASI YADAV'; $bank = 'SHASTRI LAL'; $newArrangedArray = [0]-LAL [1]-# [2]-SHASTRI [3]-### –  Feb 01 '19 at 11:48
  • @daoootim so why not just sort `$a1` by `levenshtein(metaphone()` will that works? – dWinder Feb 01 '19 at 11:59
  • yes that will work just have query how can i merge your snippet my code snippet i have used levenshtein(metaphone() **line 19** can you please suggest about mergining of code –  Feb 01 '19 at 12:05
  • @daoootim Sorting `$a1` with `levenshtein(metaphone())` require 1 word for compare not 2. Can you please try to explain better how you define the order of `$a1`? Notice that your code set "SHASTRI" in index`1` as he is the only option in the bank array so he the closest to "BAHADUR" so your code basically does hat it should - the question is what you want him to do? – dWinder Feb 01 '19 at 12:18
  • order of first string would be unchanged based on that my 2nd string bankdata will be changed there will be two arrays in which i will compare every word of 2nd string i.e bankdata with 1st string and then find then calculate `levenshtein(metaphone())` from which i will arrange the words of the string –  Feb 01 '19 at 12:19
  • word are different but the levenshtein(metaphone()) is less then that word would be considered at that index –  Feb 01 '19 at 12:25
  • @daoootim edited my answer - hope I understood you right now – dWinder Feb 01 '19 at 12:32
  • my 0 index word i.e "LAL" is missing array (size=4) `0 => string '' (length=0) 1 => string '#' (length=1) 2 => string 'SHASTR' (length=6) 3 => string '###' (length=3)` and when i pass 'SHASTRI LAL NABA' that NABA should be at 4 which is mismatch words should be placed at the last index –  Feb 01 '19 at 12:45
  • On my computer is return the correct output - please recheck (probably extra space`" "`) see [here](https://codeshare.io/21yAYX). Why? `NABA` has min levistien with `LAL` so it should be at index `0` – dWinder Feb 01 '19 at 12:52
  • i will let you know i am close to the solution just stuck with minute issue –  Feb 01 '19 at 13:06
  • @daoootim edited the first loop so will set new word only if new element has smaller levistien distance (also update the example in the snipt link – dWinder Feb 01 '19 at 13:16
  • added problem image [link](https://i.stack.imgur.com/uKEjv.jpg) NABA should be placed at the 3 position since while `levenshtein(metaphone(NABA),metaphone(YADAV)) = 3 and levenshtein(metaphone(NABA),metaphone(BAHADUR)) = 4` NABA will be at position 3 because 'YADAV' has least levenshtein as compare to 'BAHADUR' –  Feb 01 '19 at 17:27
  • All other components are placed correctly just need to arrange the remaining word NABA –  Feb 01 '19 at 17:43
  • when passing _$a1 = explode(" ", 'LAL BAHADUR SHASTRI YADAV'); $a2 = explode(" ",'SHASTRI LAL NABA RAO SINGH SANGRAM');_ as input getting `error Undefined index: Line 35` for this line $res[$y] = $a2[$x]; **when the string length of $a2 is greater** that time getting the error can you please suggest –  Feb 03 '19 at 10:22
  • 1
    @daoootim You're right. I updated the `while` loop condition. also added `if` statement before setting `$res[$y]` as I guess you want the best fit and not the one that follow (not sure if necessary but cannot harm :) ) – dWinder Feb 03 '19 at 11:09
  • This happens because `levenshtein` can return `-1` for too long string (see [documentation](http://php.net/manual/en/function.levenshtein.php)) - what should be done it depends on you - throw error? – dWinder Feb 06 '19 at 07:31
  • Getting error for this line `$res[$y] = $a2[$x];` as Undefined index: **$db = MRS R NAGA MALLESWARAMMA'; $bank = 'NAGAMALLESWARAMMA RAJULAPATI';** yes i will check and let you know dWinder –  Feb 06 '19 at 07:37
  • I didn't get error when running with your input. Result is: Array ( [0] => [1] => RAJULAPATI [2] => ## [3] => NAGAMALLESWARAMMA ) – dWinder Feb 06 '19 at 07:46
  • [2nd version of your code](https://codeshare.io/2jxKKK) I am using your second version of your code that was more beneficial for me on line 33 i am getting error –  Feb 06 '19 at 07:56
  • the 2nd version of code you provided which is more efficient to me because i dont want to crop the string can you please help out me with the change or you want me to raise new question for this –  Feb 06 '19 at 07:58
  • 1
    You can open new one if you want. I take [this](https://codeshare.io/5ZWZgQ) and run with PHP7 and worked fine – dWinder Feb 06 '19 at 08:01