Home > Back-end >  filter associative array that contains all the same value of 1
filter associative array that contains all the same value of 1

Time:10-06

I recently asked this question and got a working answer. However I have another question just a bit different from the previous one.

I have this $data, which holds an array of records from schedules table.

If you want to see the code that generates this array, you can see it from this file from LaravelDaily, it's the same code I'm working on.

The content of $data array below contains a schedule with the ids of 9 and 11.

Schedule Id 9 has the starting time of 07:00 AM and ending time of 08:00 AM (Wednesday).

Schedule Id 11 has the starting time of 07:00 AM (the same with Schedule Id 9 but only differs in the Day (Friday). I didn't include the ending time of this in the array.

$data = [
  "06:00 AM - 06:05 AM" => [
    0 => 1,
    1 => 1,
    2 => 1,
    3 => 1,
    4 => 1,
  ],
  "06:05 AM - 06:10 AM" => [
    0 => 1,
    1 => 1,
    2 => 1,
    3 => 1,
    4 => 1
  ],
  "06:10 AM - 06:15 AM" => [
    0 => 1,
    1 => 1,
    2 => 1,
    3 => 1,
    4 => 1
  ],
  "06:15 AM - 06:20 AM" => [
    0 => 1,
    1 => 1,
    2 => 1,
    3 => 1,
    4 => 1
  ],
  "06:20 AM - 06:25 AM" => [
    0 => 1,
    1 => 1,
    2 => 1,
    3 => 1,
    4 => 1
  ],
  "06:25 AM - 06:30 AM" => [
    0 => 1,
    1 => 1,
    2 => 1,
    3 => 1,
    4 => 1
  ],
  "06:30 AM - 06:35 AM" => [
    0 => 1,
    1 => 1,
    2 => 1,
    3 => 1,
    4 => 1
  ],
  "06:35 AM - 06:40 AM" => [
    0 => 1,
    1 => 1,
    2 => 1,
    3 => 1,
    4 => 1
  ],
  "06:40 AM - 06:45 AM" => [
    0 => 1,
    1 => 1,
    2 => 1,
    3 => 1,
    4 => 1
  ],
  "06:45 AM - 06:50 AM" => [
    0 => 1,
    1 => 1,
    2 => 1,
    3 => 1,
    4 => 1
  ],
  "06:50 AM - 06:55 AM" => [
    0 => 1,
    1 => 1,
    2 => 1,
    3 => 1,
    4 => 1
  ],
  "06:55 AM - 07:00 AM" => [
    0 => 1,
    1 => 1,
    2 => 1,
    3 => 1,
    4 => 1
  ],
  "07:00 AM - 07:05 AM" => [
    0 => 1,
    1 => 1,
    2 => [
      "schedule_id" => 11,
      "subject_name" => "Subject Abc",
      "rowspan" => 12
    ],
    3 => 1,
    4 => [
      "schedule_id" => 9,
      "subject_name" => "Subject Bac",
      "rowspan" => 24
    ]
  ],
  "07:05 AM - 07:10 AM" => [
    0 => 1,
    1 => 1,
    2 => 0,
    3 => 1,
    4 => 0
  ],
  "07:10 AM - 07:15 AM" => [
    0 => 1,
    1 => 1,
    2 => 0,
    3 => 1,
    4 => 0
  ],
  "07:15 AM - 07:20 AM" => [
    0 => 1,
    1 => 1,
    2 => 0,
    3 => 1,
    4 => 0
  ],
  "07:20 AM - 07:25 AM" => [
    0 => 1,
    1 => 1,
    2 => 0,
    3 => 1,
    4 => 0
  ],
  "07:25 AM - 07:30 AM" => [
    0 => 1,
    1 => 1,
    2 => 0,
    3 => 1,
    4 => 0
  ],
  "07:30 AM - 07:35 AM" => [
    0 => 1,
    1 => 1,
    2 => 0,
    3 => 1,
    4 => 0
  ],
  "07:35 AM - 07:40 AM" => [
    0 => 1,
    1 => 1,
    2 => 0,
    3 => 1,
    4 => 0
  ],
  "07:40 AM - 07:45 AM" => [
    0 => 1,
    1 => 1,
    2 => 0,
    3 => 1,
    4 => 0
  ],
  "07:45 AM - 07:50 AM" => [
    0 => 1,
    1 => 1,
    2 => 0,
    3 => 1,
    4 => 0
  ],
  "07:50 AM - 07:55 AM" => [
    0 => 1,
    1 => 1,
    2 => 0,
    3 => 1,
    4 => 0
  ],
  "07:55 AM - 08:00 AM" => [
    0 => 1,
    1 => 1,
    2 => 0,
    3 => 1,
    4 => 0
  ]
]

The previous question, what I want is to filter only the array that has another array inside it.

But now I want to remove array element if all of it's index contains only the value of 1.

Here's what it looks like:

// to be removed from the $data array
$data = [
  "06:00 AM - 06:05 AM" => [
    0 => 1,
    1 => 1,
    2 => 1,
    3 => 1,
    4 => 1
  ],
  "06:05 AM - 06:10 AM" => [
    0 => 1,
    1 => 1,
    2 => 1,
    3 => 1,
    4 => 1
  ],
  "06:10 AM - 06:15 AM" => [
    0 => 1,
    1 => 1,
    2 => 1,
    3 => 1,
    4 => 1
  ],
  "06:15 AM - 06:20 AM" => [
    0 => 1,
    1 => 1,
    2 => 1,
    3 => 1,
    4 => 1
  ],
  "06:20 AM - 06:25 AM" => [
    0 => 1,
    1 => 1,
    2 => 1,
    3 => 1,
    4 => 1
  ],
  "06:25 AM - 06:30 AM" => [
    0 => 1,
    1 => 1,
    2 => 1,
    3 => 1,
    4 => 1
  ],
  "06:30 AM - 06:35 AM" => [
    0 => 1,
    1 => 1,
    2 => 1,
    3 => 1,
    4 => 1
  ],
  "06:35 AM - 06:40 AM" => [
    0 => 1,
    1 => 1,
    2 => 1,
    3 => 1,
    4 => 1
  ],
  "06:40 AM - 06:45 AM" => [
    0 => 1,
    1 => 1,
    2 => 1,
    3 => 1,
    4 => 1
  ],
  "06:45 AM - 06:50 AM" => [
    0 => 1,
    1 => 1,
    2 => 1,
    3 => 1,
    4 => 1
  ],
  "06:50 AM - 06:55 AM" => [
    0 => 1,
    1 => 1,
    2 => 1,
    3 => 1,
    4 => 1
  ],
  "06:55 AM - 07:00 AM" => [
    0 => 1,
    1 => 1,
    2 => 1,
    3 => 1,
    4 => 1
  ]
]

The final form of the $data array is shown below.

$data = [
  "07:00 AM - 07:05 AM" => [
    0 => 1,
    1 => 1,
    2 => [
      "schedule_id" => 11,
      "subject_name" => "Subject Abc",
      "rowspan" => 12
    ],
    3 => 1,
    4 => [
      "schedule_id" => 9,
      "subject_name" => "Subject Bac",
      "rowspan" => 24
    ]
  ],
  "07:05 AM - 07:10 AM" => [
    0 => 1,
    1 => 1,
    2 => 0,
    3 => 1,
    4 => 0
  ],
  "07:10 AM - 07:15 AM" => [
    0 => 1,
    1 => 1,
    2 => 0,
    3 => 1,
    4 => 0
  ],
  "07:15 AM - 07:20 AM" => [
    0 => 1,
    1 => 1,
    2 => 0,
    3 => 1,
    4 => 0
  ],
  "07:20 AM - 07:25 AM" => [
    0 => 1,
    1 => 1,
    2 => 0,
    3 => 1,
    4 => 0
  ],
  "07:25 AM - 07:30 AM" => [
    0 => 1,
    1 => 1,
    2 => 0,
    3 => 1,
    4 => 0
  ],
  "07:30 AM - 07:35 AM" => [
    0 => 1,
    1 => 1,
    2 => 0,
    3 => 1,
    4 => 0
  ],
  "07:35 AM - 07:40 AM" => [
    0 => 1,
    1 => 1,
    2 => 0,
    3 => 1,
    4 => 0
  ],
  "07:40 AM - 07:45 AM" => [
    0 => 1,
    1 => 1,
    2 => 0,
    3 => 1,
    4 => 0
  ],
  "07:45 AM - 07:50 AM" => [
    0 => 1,
    1 => 1,
    2 => 0,
    3 => 1,
    4 => 0
  ],
  "07:50 AM - 07:55 AM" => [
    0 => 1,
    1 => 1,
    2 => 0,
    3 => 1,
    4 => 0
  ],
  "07:55 AM - 08:00 AM" => [
    0 => 1,
    1 => 1,
    2 => 0,
    3 => 1,
    4 => 0
  ]
]

Q: Why I want to remove it?

A: Because I don't want to show it in the schedule table, only the time taken from the schedule will be shown.

Q: Why not stick to the answer on your previous question?

A: I realized that I need the other array of time that is doesn't have an array inside it but has the value of 0, because the 0 is telling that that time has a schedule in it, I mean it's between the start_time and end_time of a schedule.


EDIT:

I've got a workaround as of the moment, if you have better answer feel free to post it.

The code below successfully removed all elements that holds the value of like this:

[
    0 => 1,
    1 => 1,
    2 => 1,
    3 => 1,
    4 => 1
]

The code I have:

$data = [...];

$filtered = array_filter($data,  fn ($el) => hasSchedule($el));

function hasSchedule($period) {
    for($i = 0; $i < count($period); $i  ) {
        if(is_array($period[$i])) {
            return true;
        } else {
            $sum = array_sum($period);
            if ($sum == 5) {
                return false;
            } else {
                return true;
            }
        }
    }
    return false;
}

CodePudding user response:

You can use a non-loop approach using array_filter and a custom function. To remove all 1s, we can use the array_unique function and check the result if was only one item in the result array and the first element of areay was equal to 1.

$list = [
    "07:00 AM - 07:05 AM" => [
        0 => 1,
        1 => 1,
        2 => 1,
        3 => 0,
        4 => 1,
    ],
    "07:05 AM - 07:10 AM" => [
        0 => 1,
        1 => 1,
        2 => 1,
        3 => 1,
        4 => 1,
    ],
    "07:10 AM - 07:15 AM" => [
        0 => 1,
        1 => 1,
        2 => 1,
        3 => 1,
        4 => 1,
    ],
    "07:15 AM - 07:20 AM" => [
        0 => 1,
        1 => 1,
        2 => [
            "schedule_id"  => 10,
            "time"         => "07:15 AM - 07:20 AM",
            "subject_name" => "Subject Abc",
        ],
        3 => 1,
        4 => 1,
    ]
];

function removeAllOnes($arr)
{
    if (array_filter($arr, 'is_array'))
    {
        return true;
    }
    $_new = array_unique($arr);
    return !(count($_new) == 1 && $_new[0] === 1);
}

$filtered = array_filter($list, 'removeAllOnes');
print_r($filtered);

CodePudding user response:

I posted this on the reddit question, but i'm going to post it here too to see if any SO users have any comments on it.

This works because array_filter will filter out empty arrays.

$data = array_filter($data, function($period) {
    return array_filter($period, function($item) {
        return $item !== 1;
    });
});
  • Related