How to count the recurrence of an array value - php

I want to count the recurrence of a true or false and output which has the most. Is there a predefined function to do this in PHP? So far I have done it like this (isHappy() method):
class Girl {
private $issues = [];
public function addIssue($details) {
this->issues[] = [$details, false];
return;
}
public function isHappy() {
$true = [];
$false = [];
foreach($this->issues as $issue) {
if($issue[1]) { $true[] = true; } else { $false[] = false; }
}
// what if its == to one another? do we return happy or sad?
return count($true) < count($false) ? false : true;
}
public function resolveIssue() {
for($i = 0; $i <= count($this->issues); $i++) {
if(!$this->issues[$i][1]) {
$this->issues[$i][1] = true;
break;
}
}
return;
}
}
So when I run it, I can get the average of if she is happy or not:
$her = new Girl();
$her->addIssue('Deleted our messages');
$her->addIssue('Over reacted');
$her->addIssue('Told her family to pretty much **** off');
echo $her->isHappy() ? 'it is all ok:)' : 'she hates u, hang urself.';
P.S: It should probably return false every time cos you can't win.

You want array_count_values:
function isHappy(array $issues) {
$happiness = array_count_values(array_map('intval', $issues));
return $happiness[1] > $happiness[0];
}
print_r(
isHappy([ true, false, true, true, false ])
);
See it live on 3v4l.org.
Note that array_count_values only works on string and int, so I'm mapping the given boolean to int for processing.

array_sum() type juggles for you, so simply compare the sum of all true with all issues minus the true (which yields all false):
public function isHappy() {
return ($true = array_sum($this->issues)) > (count($this->issues) - $true);
}
Get the keys where the value is true and count it, do the same for false and compare:
return count(array_keys($this->issues, true)) > count(array_keys($this->issues, false));
Or a number of other possible combinations.

Related

Leetcode linked list detect cycle - PHP

I am looking to find a way to detect cycle in linked list using Array in PHP. Please note I am aware of two pointer approach but I am keen on understanding approach if it is feasible to achieve this with php array.
in Java code sample on leetcode is as below:
public boolean hasCycle(ListNode head) {
Set<ListNode> nodesSeen = new HashSet<>();
while (head != null) {
if (nodesSeen.contains(head)) {
return true;
} else {
nodesSeen.add(head);
}
head = head.next;
}
return false;
}
Based on the given info I would rewrite it like this utilizing also an array as hashmap for visited nodes.
function hasCycle(SplDoublyLinkedList $list): bool
{
$nodesSeen = [];
$list->rewind();
while ($current = $list->current()) {
if (isset($nodesSeen[$current]))
return true;
$nodesSeen[$current] = true;
$list->next();
}
return false;
}
Testing with having a cycle on a.
$list = new SplDoublyLinkedList();
$list->push('a');
$list->push('b');
$list->push('c');
$list->push('a');
var_dump(hasCycle($list));
true
Testing with having no cycle.
$list = new SplDoublyLinkedList();
$list->push('a');
$list->push('b');
$list->push('c');
$list->push('d');
var_dump(hasCycle($list));
false
one more approach I have come across (no that efficient though):
function hasCycle($head) {
$prev = [];
while($head){
if(in_array($head, $prev)) {
return true;
}
$prev[] = $head;
$head= $head->next;
}
return false;
}

PHP Check if multiple values in array are all positive or all negative or partly

I have an array with 2 possible values negative and positive. If all the values are positive my function has to return positive.
If all values are negative my function has to return negative. If the values are a mix then my function has to return partly.
My code always returns partly, unfortunately, I don't know why.
const RESULT_OF_SEARCH_POSITIVE = "positive";
const RESULT_OF_SEARCH_NEGATIVE = "negative";
const RESULT_OF_SEARCH_PARTLY = "partly";
...
private function calculateResultOfSearch(array $imagesResultArray)
{
if (array_unique($imagesResultArray) === self::RESULT_OF_SEARCH_POSITIVE) {
return self::RESULT_OF_SEARCH_POSITIVE;
} elseif(array_unique($imagesResultArray) === self::RESULT_OF_SEARCH_NEGATIVE)
{
return self::RESULT_OF_SEARCH_NEGATIVE;
} else {
return self::RESULT_OF_SEARCH_PARTLY;
}
}
As we know the count() function always returns the count of the array. So it goes to the else case in every match of the condition.
You should try something like this:
class Demo{
const RESULT_OF_SEARCH_POSITIVE = "positive";
const RESULT_OF_SEARCH_NEGATIVE = "negative";
const RESULT_OF_SEARCH_PARTLY = "partly";
function calculateResultOfSearch(array $imagesResultArray)
{
if (count(array_count_values($imagesResultArray)) == 1 && $imagesResultArray[0] === self::RESULT_OF_SEARCH_POSITIVE) {
return current($imagesResultArray);
} elseif(count(array_count_values($imagesResultArray)) == 1 && $imagesResultArray[0]== self::RESULT_OF_SEARCH_NEGATIVE) {
return self::RESULT_OF_SEARCH_NEGATIVE;
} else {
return self::RESULT_OF_SEARCH_PARTLY;
}
}
}
$demo = new Demo();
print_r($demo->calculateResultOfSearch(["positive","positive"]));
array_count_values() returns an array using the values of the array as keys and their frequency in the array as values.
Here is a simple way to check the values of an array containing the same value using array_count_values function and count if all keys are the same this should equal.
Reference
A much simplified version of the code which if array_unique just has 1 value, then return it (also I only call it once rather than repeatedly calling it which is very inefficient)...
private function calculateResultOfSearch(array $imagesResultArray)
{
$unique = array_unique($imagesResultArray);
return (count($unique) == 1 ) ? $unique[0]
: self::RESULT_OF_SEARCH_PARTLY;
}
Edit:
I am unfortuantly back after realising I've wasted 20% of the lines I wrote :( If all the items are the same, I can just return the first item of the array passed in so I don't need to store the result of array_unique() at all :-/
private function calculateResultOfSearch(array $imagesResultArray)
{
return ( count(array_unique($imagesResultArray)) == 1 ) ?
$imagesResultArray[0]: RESULT_OF_SEARCH_PARTLY;
}
Try this code :
const RESULT_OF_SEARCH_POSITIVE = "positive";
const RESULT_OF_SEARCH_NEGATIVE = "negative";
const RESULT_OF_SEARCH_PARTLY = "partly";
...
private function calculateResultOfSearch(array $imagesResultArray)
{
if (!in_array(RESULT_OF_SEARCH_NEGATIVE)) {
return self::RESULT_OF_SEARCH_POSITIVE;
} elseif(!in_array(RESULT_OF_SEARCH_POSITIVE)) {
return self::RESULT_OF_SEARCH_NEGATIVE;
} else {
return self::RESULT_OF_SEARCH_PARTLY;
}
}
You're comparing (count(array_unique($imagesResultArray)) which return an int with self::RESULT_OF_SEARCH_POSITIVE or self::RESULT_OF_SEARCH_NEGATIVE which return a string equals to either "positive" or "negative" so it's always false.
You need to change your conditions.
EDIT after OP's edit
PHP: array_unique
Takes an input array and returns a new array without duplicate values.
In your case you might want to check if the resulting array only has one element equals to "positive" or "negative".
$newArray = array_unique($imagesResultArray);
if (count($newArray) == 1 && $newArray[0] === self::RESULT_OF_SEARCH_POSITIVE) {
return self::RESULT_OF_SEARCH_POSITIVE;
} elseif(count($newArray) == 1 && $newArray[0] === self::RESULT_OF_SEARCH_NEGATIVE) {
return self::RESULT_OF_SEARCH_NEGATIVE;
} else {
return self::RESULT_OF_SEARCH_PARTLY;
}
With your guys answers I came to this "clean" solution.
private function calculateResultOfSearch(array $imagesResultArray)
{
$results = array_unique($imagesResultArray);
if(count($results) == 1 && $results[0] === self::RESULT_OF_SEARCH_NEGATIVE) {
return self::RESULT_OF_SEARCH_NEGATIVE;
}
if(count($results) == 1 && $results[0] === self::RESULT_OF_SEARCH_POSITIVE) {
return self::RESULT_OF_SEARCH_POSITIVE;
}
return self::RESULT_OF_SEARCH_PARTLY;
}

Array Filter limit amount of results PHP

I have the following method
public function getNextAvailableHousesToAttack(\DeadStreet\ValueObject\House\Collection $collection, $hordeSize)
{
$houses = $collection->getHouses();
$housesThatCanBeAttacked = array_filter($houses, function($house) use (&$hordeSize) {
if(!isset($house)) {
return false;
}
$house = $this->houseModel->applyMaxAttackCapacity($house, $hordeSize);
if($this->houseModel->isAttackable($house)) {
return $house;
}
return false;
});
return $housesThatCanBeAttacked;
However, this array can be huge.
I want to limit $housesThatCanBeAttacked to whatever the size of $hordeSize is set to, as I only need as many houses as there are zombies in the horde to attack this round.
However, this array $housesThatCanBeAttacked could end up containing 1 million houses, where there are only 100 in the zombie horde.
Is there a way to limit the size of this array built from the callback?
You could simply use a loop, and stop processing the array when you have enough houses.
$houses = $collection->getHouses();
housesThatCanBeAttacked[];
$i = 0;
foreach ($houses as $house) {
$house = $this->houseModel->applyMaxAttackCapacity($house, $hordeSize);
if ($this->houseModel->isAttackable($house)) {
housesThatCanBeAttacked[] = $house;
if (++$i == $hordeSize) {
break;
}
}
}
I would add a counter of houses outside of callback and use it inside callback to skip all excessive houses. Here is how a solution can look like:
public function getNextAvailableHousesToAttack(\DeadStreet\ValueObject\House\Collection $collection, $hordeSize)
{
$houses = $collection->getHouses();
$counter = $hordeSize;
$housesThatCanBeAttacked = array_filter($houses, function($house) use (&$hordeSize, &$counter) {
if($counter == 0 && !isset($house)) {
return false;
}
$house = $this->houseModel->applyMaxAttackCapacity($house, $hordeSize);
if($this->houseModel->isAttackable($house)) {
$counter--;
return $house;
}
return false;
});
return $housesThatCanBeAttacked;
This way you array_filter won't return more then $counter values.

Test only evaluating first element of array

I loop through the values of a form, to check that each field has 4 digits. My problem is currently it validates true or false only on the match for the first field $card1...
function cardcheck ($card1,$card2,$card3,$card4)
{
$cards = array($card1,$card2,$card3,$card4);
$regex = "/[0-9]{4}/";
for ($i=0;$i<4;$i++)
if (! preg_match ($regex,$cards[$i]))
{
return false;
}
else
{
return true;
}
}
You're returning (by using return ...) something in the first iteration every time (boolean condition with an else).
You need to put the return true outside the loop statement:
function cardcheck ($card1,$card2,$card3,$card4)
{
$cards = array($card1,$card2,$card3,$card4);
$regex = "/[0-9]{4}/";
for ($i=0;$i<4;$i++) {
if (! preg_match ($regex,$cards[$i])) {
return false;
}
}
return true;
}
function cardcheck ($card1,$card2,$card3,$card4)
{
$cards = array($card1,$card2,$card3,$card4);
$regex = "/[0-9]{4}/";
for ($i=0;$i<4;$i++)
if (! preg_match ($regex,$cards[$i]))
{
return false;
}
return true;
}

More concise way to check to see if an array contains only numbers (integers)

How do you verify an array contains only values that are integers?
I'd like to be able to check an array and end up with a boolean value of true if the array contains only integers and false if there are any other characters in the array. I know I can loop through the array and check each element individually and return true or false depending on the presence of non-numeric data:
For example:
$only_integers = array(1,2,3,4,5,6,7,8,9,10);
$letters_and_numbers = array('a',1,'b',2,'c',3);
function arrayHasOnlyInts($array)
{
foreach ($array as $value)
{
if (!is_int($value)) // there are several ways to do this
{
return false;
}
}
return true;
}
$has_only_ints = arrayHasOnlyInts($only_integers ); // true
$has_only_ints = arrayHasOnlyInts($letters_and_numbers ); // false
But is there a more concise way to do this using native PHP functionality that I haven't thought of?
Note: For my current task I will only need to verify one dimensional arrays. But if there is a solution that works recursively I'd be appreciative to see that to.
$only_integers === array_filter($only_integers, 'is_int'); // true
$letters_and_numbers === array_filter($letters_and_numbers, 'is_int'); // false
It helps to define two helper, higher-order functions:
/**
* Tell whether all members of $elems validate the $predicate.
*
* all(array(), 'is_int') -> true
* all(array(1, 2, 3), 'is_int'); -> true
* all(array(1, 2, 'a'), 'is_int'); -> false
*/
function all($elems, $predicate) {
foreach ($elems as $elem) {
if (!call_user_func($predicate, $elem)) {
return false;
}
}
return true;
}
/**
* Tell whether any member of $elems validates the $predicate.
*
* any(array(), 'is_int') -> false
* any(array('a', 'b', 'c'), 'is_int'); -> false
* any(array(1, 'a', 'b'), 'is_int'); -> true
*/
function any($elems, $predicate) {
foreach ($elems as $elem) {
if (call_user_func($predicate, $elem)) {
return true;
}
}
return false;
}
<?php
$only_integers = array(1,2,3,4,5,6,7,8,9,10);
$letters_and_numbers = array('a',1,'b',2,'c',3);
function arrayHasOnlyInts($array){
$test = implode('',$array);
return is_numeric($test);
}
echo "numbers:". $has_only_ints = arrayHasOnlyInts($only_integers )."<br />"; // true
echo "letters:". $has_only_ints = arrayHasOnlyInts($letters_and_numbers )."<br />"; // false
echo 'goodbye';
?>
Another alternative, though probably slower than other solutions posted here:
function arrayHasOnlyInts($arr) {
$nonints = preg_grep('/\D/', $arr); // returns array of elements with non-ints
return(count($nonints) == 0); // if array has 0 elements, there's no non-ints
}
There's always array_reduce():
array_reduce($array, function($a, $b) { return $a && is_int($b); }, true);
But I would favor the fastest solution (which is what you supplied) over the most concise.
function arrayHasOnlyInts($array) {
return array_reduce(
$array,
function($result,$element) {
return is_null($result) || $result && is_int($element);
}
);
}
returns true if array has only integers, false if at least one element is not an integer, and null if array is empty.
Why don't we give a go to Exceptions?
Take any built in array function that accepts a user callback (array_filter(), array_walk(), even sorting functions like usort() etc.) and throw an Exception in the callback. E.g. for multidimensional arrays:
function arrayHasOnlyInts($array)
{
if ( ! count($array)) {
return false;
}
try {
array_walk_recursive($array, function ($value) {
if ( ! is_int($value)) {
throw new InvalidArgumentException('Not int');
}
return true;
});
} catch (InvalidArgumentException $e) {
return false;
}
return true;
}
It's certainly not the most concise, but a versatile way.

Categories