Рассчитать пару вхождений

1

Допустим, у меня есть следующая строка:

foo,bar,baz
bar,foo
quux,baz,foo

Я хотел бы создать список пар, состоящих более чем из одной пары, поэтому вы получите следующий массив:

[['foo', 'bar'], ['foo', 'baz']],

Возможно, это звучит глупо, но я уже некоторое время бьюсь о том, как это сделать. Другая проблема заключается в том, что размер набора составляет пару МБ, и, если возможно, код должен быть очень эффективным.

Кто-нибудь может подтолкнуть меня в правильном направлении? Может быть, с каким-то алгоритмом эффективности или просто примером кода?

  • 0
    Термины всегда разделяются запятыми?
  • 0
    строки с \ n и термы с запятой
Показать ещё 2 комментария
Теги:
arrays
pair

2 ответа

0

Разделите и победите.

Подготовьте список всех пар одной строки, а затем соедините все строки списка пар и узнайте их повторяющиеся.

$string = <<<STRING
foo,bar,baz
bar,foo
quux,baz,foo
STRING;

$lines = array_map(function ($line) {
    // split lines into words
    $words = explode(',', $line);

    // filter repeats
    $words = array_unique($words);

    // sort words
    sort($words);

    return $words;
}, preg_split('/\R/', $string));

function pairs($words) {
    $length = count($words);

    if ($length < 2) {
        throw new Exception('No pairs if length < 2');
    }

    $pairs = [];

    // iterate from start to one before last word
    for ($i = 0; $i < $length - 1; $i++) {
        // iterate from next word to end
        for ($j = $i + 1; $j < $length; $j++) {
            $pairs[] = [$words[$i], $words[$j]];
        }
    }

    return $pairs;
}

$allPairs = [];
$nonUniquePairs = [];
foreach ($lines as $words) {
    $pairs = pairs($words);
    foreach ($pairs as $pair) {
        // check if pair is already added and not in $nonUniquePairs array
        if (in_array($pair, $allPairs, true) && !in_array($pair, $nonUniquePairs, true)) {
            $nonUniquePairs[] = $pair;
        }
    }

    $allPairs = array_unique(array_merge($allPairs, $pairs), SORT_REGULAR);
}

И это будет результат:

'allPairs' => 
    array (size=5)
      0 => 
        array (size=2)
          0 => string 'bar' (length=3)
          1 => string 'baz' (length=3)
      1 => 
        array (size=2)
          0 => string 'bar' (length=3)
          1 => string 'foo' (length=3)
      2 => 
        array (size=2)
          0 => string 'baz' (length=3)
          1 => string 'foo' (length=3)
      4 => 
        array (size=2)
          0 => string 'baz' (length=3)
          1 => string 'quux' (length=4)
      5 => 
        array (size=2)
          0 => string 'foo' (length=3)
          1 => string 'quux' (length=4)
'nonUniquePairs' => 
    array (size=2)
      0 => 
        array (size=2)
          0 => string 'bar' (length=3)
          1 => string 'foo' (length=3)
      1 => 
        array (size=2)
          0 => string 'baz' (length=3)
          1 => string 'foo' (length=3)
0
<?
$str = 'foo,bar,baz,baz,b
bar,foo,b,a
quux,b,baz,foo,a';


// prepare a working array    
$array = array_map(function ($i) { return array_unique(array_map('trim', explode(',', $i))); }, explode("\n", $str));

// find intersects of all arrays
$res = array();
for($i=0; $i < count($array); $i++)
   for($j=$i+1; $j < count($array); $j++) {
       $temp = array_unique(array_intersect($array[$i], $array[$j]));
       sort($temp);     // Reaet indexes
       $res[] = $temp;
       } 

// Gather unique pairs
$pairs = array();
foreach($res as $item) 
   for($i=0; $i < count($item); $i++)
      for($j=$i+1; $j < count($item); $j++) {
          $c = true;
          foreach($pairs as $p)
              if(!array_diff($p, array($item[$i], $item[$j]))) {
                 $c = false; 
                 break;
                 }
         if($c) $pairs[] = array($item[$i], $item[$j]);
         }
print_r($pairs);

результат

[ [b, bar], [b, foo], [bar, foo], [b, baz], [baz, foo], [a,b], [a, foo] ]

Демо на eval

Ещё вопросы

Сообщество Overcoder
Наверх
Меню