$item) { if ($item === $needle && ($key === null || $key === $k)) { return true; } elseif (\is_array($item)) { $found = self::inArrayRecursive($needle, $item, $key); if ($found) { return true; } } } return $found; } /** * Check if any of the needles are in the array * * @param array $needles Needles for search * @param array $haystack Haystack for search * * @return bool * * @since 1.0.0 */ public static function anyInArray(array $needles, array $haystack) : bool { foreach ($needles as $needle) { if (\in_array($needle, $haystack)) { return true; } } return false; } /** * Check if all of the needles are in the array * * @param array $needles Needles for search * @param array $haystack Haystack for search * * @return bool * * @since 1.0.0 */ public static function allInArray(array $needles, array $haystack) : bool { foreach ($needles as $needle) { if (!\in_array($needle, $haystack)) { return false; } } return true; } /** * Convert array to csv string. * * @param array $data Data to convert * @param string $delimiter Delim to use * @param string $enclosure Enclosure to use * @param string $escape Escape to use * * @return string * * @since 1.0.0 */ public static function arrayToCsv(array $data, string $delimiter = ';', string $enclosure = '"', string $escape = '\\') : string { $outstream = \fopen('php://memory', 'r+'); if ($outstream === false) { throw new \Exception(); // @codeCoverageIgnore } foreach ($data as $line) { /** @noinspection PhpMethodParametersCountMismatchInspection */ \fputcsv($outstream, $line, $delimiter, $enclosure, $escape); } \rewind($outstream); $csv = \stream_get_contents($outstream); \fclose($outstream); return $csv === false ? '' : $csv; } /** * Get array value by argument id. * * Useful for parsing command line parsing * * @param string $id Id to find * @param string[] $args CLI command list * * @return null|string * * @since 1.0.0 */ public static function getArg(string $id, array $args) : ?string { if (\is_numeric($id)) { return $args[(int) $id] ?? null; } if (($key = \array_search($id, $args)) === false || $key === \count($args) - 1) { return null; } return \trim($args[(int) $key + 1], '" '); } /** * Check if flag is set * * @param string $id Id to find * @param string[] $args CLI command list * * @return int * * @since 1.0.0 */ public static function hasArg(string $id, array $args) : int { return ($key = \array_search($id, $args)) === false ? -1 : (int) $key; } /** * Flatten array * * Reduces multi dimensional array to one dimensional array. Flatten tries to maintain the index as far as possible. * * @param array $array Multi dimensional array to flatten * * @return array * * @since 1.0.0 */ public static function arrayFlatten(array $array) : array { // see collection collapse as alternative?! $flat = []; $stack = \array_values($array); while (!empty($stack)) { $value = \array_shift($stack); if (\is_array($value)) { $stack = \array_merge(\array_values($value), $stack); } else { $flat[] = $value; } } return $flat; } /** * Sum of array elements * * @param array $array Array to sum * @param int $start Start index * @param int $count Amount of elements to sum * * @return int|float * * @since 1.0.0 */ public static function arraySum(array $array, int $start = 0, int $count = 0) : int | float { $count = $count === 0 ? \count($array) : $start + $count; $sum = 0; $array = \array_values($array); for ($i = $start; $i <= $count - 1; ++$i) { $sum += $array[$i]; } return $sum; } /** * Sum multi dimensional array * * @param array $array Multi dimensional array to flatten * * @return mixed * * @since 1.0.0 */ public static function arraySumRecursive(array $array) : mixed { return \array_sum(self::arrayFlatten($array)); } /** * Applying abs to every array value * * @param array $values Numeric values * * @return array * * @since 1.0.0 */ public static function abs(array $values) : array { $abs = []; foreach ($values as $value) { $abs[] = \abs($value); } return $abs; } /** * Power all values in array. * * @param array $values Values to square * @param float $exp Exponent * * @return float[] * * @since 1.0.0 */ public static function power(array $values, int | float $exp = 2) : array { $squared = []; foreach ($values as $value) { $squared[] = $value ** $exp; } return $squared; } /** * Sqrt all values in array. * * @param array $values Values to sqrt * * @return array * * @since 1.0.0 */ public static function sqrt(array $values) : array { $squared = []; foreach ($values as $value) { $squared[] = \sqrt($value); } return $squared; } /** * Get the associative difference of two arrays. * * @param array $values1 Array 1 * @param array $values2 Array 2 * * @return array * * @since 1.0.0 */ public static function array_diff_assoc_recursive(array $values1, array $values2) : array { $diff = []; foreach ($values1 as $key => $value) { if (\is_array($value)) { if (!\array_key_exists($key, $values2) || !\is_array($values2[$key])) { $diff[$key] = $value; } else { $subDiff = self::array_diff_assoc_recursive($value, $values2[$key]); if (!empty($subDiff)) { $diff[$key] = $subDiff; } } } elseif (!\array_key_exists($key, $values2) || $values2[$key] !== $value) { $diff[$key] = $value; } } return $diff; } /** * Get the dot product of two arrays * * @param array $value1 Value 1 is a matrix or a vector * @param array $value2 Value 2 is a matrix or vector (cannot be a matrix if value1 is a vector) * * @return array * * @since 1.0.0 */ public static function dot(array $value1, array $value2) : int|float|array { $m1 = \count($value1); $n1 = ($isMatrix1 = \is_array($value1[0])) ? \count($value1[0]) : 1; $m2 = \count($value2); $n2 = ($isMatrix2 = \is_array($value2[0])) ? \count($value2[0]) : 1; $result = null; if ($isMatrix1 && $isMatrix2) { if ($m2 !== $n1) { throw new InvalidDimensionException($m2 . 'x' . $n2 . ' not compatible with ' . $m1 . 'x' . $n1); } $result = [[]]; for ($i = 0; $i < $m1; ++$i) { // Row of 1 for ($c = 0; $c < $n2; ++$c) { // Column of 2 $temp = 0; for ($j = 0; $j < $m2; ++$j) { // Row of 2 $temp += $value1[$i][$j] * $value2[$j][$c]; } $result[$i][$c] = $temp; } } } elseif (!$isMatrix1 && !$isMatrix2) { if ($m1 !== $m2) { throw new InvalidDimensionException($m1 . ' vs. ' . $m2); } $result = 0; for ($i = 0; $i < $m1; ++$i) { $result += $value1[$i] * $value2[$i]; } } elseif ($isMatrix1 && !$isMatrix2) { $result = []; for ($i = 0; $i < $m1; ++$i) { // Row of 1 $temp = 0; for ($c = 0; $c < $m2; ++$c) { // Row of 2 $temp += $value1[$i][$c] * $value2[$c]; } $result[$i] = $temp; } } else { throw new \InvalidArgumentException(); } return $result; } /** * Calculate the vector corss product * * @param array $vector1 First 3 vector * @param array $vector2 Second 3 vector * * @return array * * @since 1.0.0 */ public function cross3(array $vector1, array $vector2) : array { return [ $vector1[1] * $vector2[2] - $vector1[2] * $vector2[1], $vector1[2] * $vector2[0] - $vector1[0] * $vector2[2], $vector1[0] * $vector2[1] - $vector1[1] * $vector2[0], ]; } }