Sergio Marani
Sergio Marani

Reputation: 87

Restructure 2 columns of a 2d array to invert the many-to-many relationships

I've got an array with 3 parameters: date, events and tags.

This is the array:

    Array
    (
        [date] => 1554328800
        [events] => Array
            (
                [0] => 130
                [1] => 131
                [2] => 163
            )

        [tags] => Array
            (
                [0] => 4
                [1] => "1,3,4"
                [2] => "1,3"
            )

    )

The relationship between events and tags is in the key, so the event 130 that has position 0 has tag 4.

As you can see there are some tags repeated (events 130 and 131 or 131 and 163).

How could I get an array with only repeated events like this:

    Array
    (
      [0] => Array
      (
        [date] => 1554328800
        [events] => Array
            (
                [0] => 130
                [1] => 131
            )

        [tags] => 4
      )
      [1] => Array
      (
        [date] => 1554328800
        [events] => Array
            (
                [0] => 131
                [1] => 163
            )

        [tags] => Array
           (
               [0] => 1
               [1] => 3
           )
      )
    )

Upvotes: 4

Views: 104

Answers (3)

trincot
trincot

Reputation: 350310

Here is how I would do it:

  1. List the events per individual tag

    This will give several sets of events, which can be used in the next step

  2. List the tags per set of events that occurred in previous step

  3. Produce the result from step 2

Here is the code, also runnable at 3v4l.org:

// Sample input
$data = [
    "date" => 1554328800,
    "events" => [130, 131, 163],
    "tags" => [4, "1,3,4", "1,3"]
];

// 1. List the events per individual tag
foreach($data["tags"] as $i => $val) {
    $vals = explode(",", $val);
    foreach($vals as $val) {
        $eventsByTag[$val][] = $data["events"][$i];
    }
}

// 2. List the tags per set of events
foreach($eventsByTag as $tag => $events) {
    sort($events, SORT_NUMERIC);
    $tagsByEvents[implode(",", $events)][] = $tag;
}

// 3. produce the result
foreach($tagsByEvents as $events => $tags) {
    $events = explode(",", $events);
    if (count($tags) == 1) $tags = $tags[0];
    $result[] = [
        "date" => $data["date"],
        "events" => $events,
        "tags" => $tags
    ];
}

print_r($result);

Upvotes: 2

bob_1982
bob_1982

Reputation: 733

pl check this

$sarr=['date'=>1554328800,
    'events'=>
    [
                130,
                131,
                163
    ],
    'tags'=>
    [
        4,
        "1,3,4",
        "1,3"  
    ]

    ]; 
$tagarr=[];
$events=$sarr['events'];
$index=0;
foreach( $sarr['tags'] as $tag)  
{ 
 $t=explode(",",$tag);
 $cnt=count($t);
 for($idx=0;$idx<$cnt;$idx++)
  $tagarr[$t[$idx]][]=$events[$index];
 $index++;
}
$cnt=count($tagarr);
$myarr=[];
foreach($tagarr as $key=>$value)
 {
  $myarr[]=['date'=>$sarr['date'],'events'=>$value,'tags'=>$key];
  }
ec ho "<pre>";
print_r($myarr);
echo "</pre>";

output is

Array
( 
   [0] => Array
       (
          [date] => 1554328800
          [events] => Array
              (
                  [0] => 130
                  [1] => 131
              )

         [tags] => 4
    )

[1] => Array
    (
        [date] => 1554328800
        [events] => Array
            (
                [0] => 131
                [1] => 163
            )

        [tags] => 1
    )

[2] => Array
    (
        [date] => 1554328800
        [events] => Array
            (
                [0] => 131
                [1] => 163
            )

        [tags] => 3
    )

  )

Upvotes: -1

PHPnoob
PHPnoob

Reputation: 614

$date = array();
$date['date'] = 1554328800;
$date['events'] = array(130, 131, 163);
$date['tags'] = array(4, "1,3,4", "1,3");

$events_by_tag = array(); //gather events grouped by tag
foreach ($date['events'] as $pos => $event) { //parse all events

    if (is_string($date['tags'][$pos])) { //if tag is a string <=> if there are more than one tag for the current event

        $tags = explode(',', $date['tags'][$pos]); //explode string to loop over the tags
        foreach ($tags as $tag) {
            if (is_array($events_by_tag[$tag])) { //if tag has already been found and then an array exists to store it
                array_push($events_by_tag[$tag], $event);
            } else {
                $events_by_tag[$tag] = array($event); //else create an array for the next times this tag will be found and store it inside
            }
        }

    } else { //if there's a single tag which is a integer

        if (is_array($events_by_tag[$tag])) { //if tag has already been found and then an array exists to store it
            array_push($events_by_tag[$date['tags'][$pos]], $event);
        } else {
            $events_by_tag[$date['tags'][$pos]] = array($event); //else create an array for the next times this tag will be found and store it inside
        }

    }

}

$result_array = array(); //final array reorganized + date
foreach ($events_by_tag as $tag => $events) {
    $tmp_array['date'] = $date['date'];
    $tmp_array['events'] = $events;
    $tmp_array['tags'] = $tag;
    array_push($result_array, $tmp_array);
}

This is NOT exactly what you expected because it will not merge events sharing tags. I think this part needs another post to be developed, but otherwise I can modify my answer to give you the way to go if necessary.

Upvotes: -1

Related Questions