Compare two integer and count matching numbers - php

I have two integers for example "12345" and "98754", they have a count of 2 matching numbers
namely 4 and 5, the order doesnt matter.
Now: How do I check something like that in PHP?

You can split the inputs to arrays and use array_intersect to find matching numbers.
$a = 12345;
$b = 98754;
//Create arrays of the numbers
$a = str_split($a);
$b = str_split($b);
// Find matching numbers
$matching = array_intersect($a, $b);
Var_dump($matching);
// Output: 4,5
Echo count($matching);
// Output: 2
https://3v4l.org/8tS3q

Convert the numbers in to strings
create a loop from 0-9 to check for the appearance of a number in both strings using strstr() or similar
store the number in an array if it appears in both
Edit:
Code-centric solution:
$a = 1231534;
$b = 89058430;
$matches = compare( $a, $b );
print count($matches);
function compare ( $a, $b ) {
$str_a = (string) $a;
$str_b = (string) $b;
$matches = [];
for($i=0;$i<=9;$i++) {
if (strstr($str_a, (string)$i) && strstr($str_b,(string)$i)) $matches[] = $i;
}
return $matches;
}

Added an example here that counts digits that occur in both numbers.
If multiple digits occur in both, these are included:
<?php
function digits_in_both($x, $y)
{
$in_both = [];
$split_y = str_split($y);
foreach(str_split($x) as $n) {
$key = array_search($n, $split_y);
if($key !== false) {
$in_both[] = $n;
unset($split_y[$key]);
}
}
return $in_both;
}
$in_both = digits_in_both(123445, 4456);
var_export($in_both);
var_dump(count($in_both));
Output:
array (
0 => '4',
1 => '4',
2 => '5',
)int(3)
Contrary to what you expect with array_intersect, order matters as demonstrated here:
var_export(array_intersect(str_split('024688'), str_split('248')));
var_export(array_intersect(str_split('248'), str_split('024688')));
Output:
array (
1 => '2',
2 => '4',
4 => '8',
5 => '8',
)array (
0 => '2',
1 => '4',
2 => '8',
)

Related

PHP Array split string and Integers

Below is an array of strings and numbers. How could the string and number values be split into separate arrays (with strings in one array and numbers in another array)?
array('a','b','c',1,2,3,4,5,'t','x','w')
You could also do this in one line using array_filter()
$numbers = array_filter($arr,function($e){return is_numeric($e);});
$alphas = array_filter($arr,function($e){return !is_numeric($e);});
print_r($numbers);
print_r($alphas);
Loop through them, check if is_numeric and add to appropriate array:
$original = array('a','b','c',1,2,3,4,5,'t','x','w');
$letters = array();
$numbers = array();
foreach($original as $element){
if(is_numeric($element)){
$numbers[] = $element;
}else{
$letters[] = $element;
}
}
https://3v4l.org/CAvVp
Using a foreach() like in #jnko's answer will be most performant because it only iterates over the array one time.
However, if you are not concerned with micro-optimization and prefer to write concise or functional-style code, then I recommend using array_filter() with is_numeric() calls, then making key comparisons between the first result and the original array.
Code: (Demo)
$array = ['a','b',0,'c',1,2,'ee',3,4,5,'t','x','w'];
$numbers = array_filter($array, 'is_numeric');
var_export($numbers);
var_export(array_diff_key($array, $numbers));
Output:
array (
2 => 0,
4 => 1,
5 => 2,
7 => 3,
8 => 4,
9 => 5,
)
array (
0 => 'a',
1 => 'b',
3 => 'c',
6 => 'ee',
10 => 't',
11 => 'x',
12 => 'w',
)
$data = array('a','b','c',1,2,3,4,5,'t','x','w');
$integerArray = array();
$stringArray = array();
$undefinedArray = array();
foreach($data as $temp)
{
if(gettype($temp) == "integer")
{
array_push($integerArray,$temp);
}elseif(gettype($temp) == "string"){
array_push($stringArray,$temp);
}else{
array_push($undefinedArray,$temp);
}
}

Implode columnar values between two arrays into a flat array of concatenated strings

I have two arrays, $array_A and $array_B. I'd like to append the first value from $array_B to the end of the first value of $array_A and repeat this approach for all elements in both arrays.
$array_A = ['foo', 'bar', 'quuz'];
$array_B = ['baz', 'qux', 'corge'];
Expected output after squishing:
['foobaz', 'barqux', 'quuzcorge']
array_merge($array_A, $array_B) simply appends array B onto array A, and array_combine($array_A, $array_B) sets array A to be the key for array B, neither of which I want. array_map seems pretty close to what I want, but seems to always add a space between the two, which I don't want.
It would be ideal for the lengths of each array it to be irrelevant (e.g. array A has five entries, array B has seven entries, extra entries are ignored/trimmed) but not required.
// updated version
$a = ['a', 'b', 'c'];
$b = ['d', 'e', 'f', 'g'];
print_r(array_map('implode', array_map(null, $a, $b)));
Probably the fastest code, but more verbose than other options.
//updated version
$array_A = ['foo', 'bar', 'quuz'];
$array_B = ['baz', 'qux', 'corge'];
for ($i = 0, $c = count($array_A); $i<$c; $i++) {
$result[$i] = $array_A[$i].$array_B[$i];
}
var_dump($result);
There isn't an array function in PHP that does exactly that. However, you can write one yourself, like this one:
function array_zip($a1, $a2) {
$out = [];
for($i = 0; $i < min(sizeof($a1), sizeof($a2)); $i++) {
array_push($out, $a1[$i] . $a2[$i]);
}
return $out;
}
So given these arrays and running it:
$a = ["foo", "bar"];
$b = ["baz", "qux"];
print_r(array_zip($a, $b));
You would get:
Array
(
[0] => foobaz
[1] => barqux
)
Try this:
$A = ['foo', 'bar'];
$B = ['baz', 'qux'];
function arraySquish($array)
{
$new = [''];
foreach($array as $val) {
$new[0] .= $val;
}
return $new;
}
$A = arraySquish($A);
$B = arraySquish($B);
echo '<pre>';
print_r($A);
print_r($B);
echo '</pre>';
PHP Fiddle here.
An explicit array_map:
<?php
$colours = ['red', 'white', 'blue'];
$items = ['robin', 'cloud', 'mountain'];
$squished =
array_map(
function($colour, $item) {
return $colour.$item;
},
$colours,
$items
);
var_export($squished);
Output:
array (
0 => 'redrobin',
1 => 'whitecloud',
2 => 'bluemountain',
)
If you want to only go as far as the smallest array, you could either return null if either entries are null, and then filter your result.
Or truncate the arrays to the same length:
$b = array_intersect_key($b, $a);
$a = array_intersect_key($a, $b);
Regardless of if both arrays have the same length or if one is longer than the other or in what order the arrays occur in, the following technique will "squish" the values into a flat array of strings.
array_map() only needs to be called once and implode()'s default "glue" string is an empty string -- so it can be omitted.
Code: (Demo)
$a = ['a', 'b', 'c'];
$b = ['d', 'e', 'f', 'g'];
var_export(array_map(fn() => implode(func_get_args()), $a, $b));
Or consolidate the column data with spread operator: (Demo)
var_export(array_map(fn(...$column) => implode($column), $a, $b));
Output:
array (
0 => 'ad',
1 => 'be',
2 => 'cf',
3 => 'g',
)

exploding string with multiple delimiter [duplicate]

This question already has answers here:
PHP - split String in Key/Value pairs
(5 answers)
Convert backslash-delimited string into an associative array
(4 answers)
Closed 12 months ago.
i have a string like
$str = "1-a,2-b,3-c";
i want to convert it into a single array like this
$array = [
1 => "a",
2 => "b",
3 => "c"
];
what i do is
$str = "1-a,2-b,3-c";
$array = [];
$strex = explode(",", $str);
foreach ($strex as $str2) {
$alphanumeric = explode("-", $str2);
$array[$alphanumeric[0]] = $alphanumeric[1];
}
can i do this in a better way?
You can use preg_match_all for this:
<?php
$str = "1-a,2-b,3-c";
preg_match_all('/[0-9]/', $str, $keys);
preg_match_all('/[a-zA-Z]/', $str, $values);
$new = array_combine($keys[0], $values[0]);
echo '<pre>'. print_r($new, 1) .'</pre>';
here we take your string, explode() it and then preg_match_all the $value using patterns:
/[0-9]/ -> numeric value
/[a-zA-Z]/ -> letter
then use array_combine to get it into one array
Thanks to u_mulder, can shorten this further:
<?php
$str = "1-a,2-b,3-c";
preg_match_all('/(\d+)\-([a-z]+)/', $str, $matches);
$new = array_combine($matches[1], $matches[2]);
echo '<pre>'. print_r($new, 1) .'</pre>';
just a little benchmark:
5000 iterations
Debian stretch, php 7.3
parsed string: "1-a,2-b,3-c,4-d,5-e,6-f,7-g,8-h,9-i"
[edit] Updated with the last 2 proposals [/edit]
You can use preg_split with array_filter and array_combine,
function odd($var)
{
// returns whether the input integer is odd
return $var & 1;
}
function even($var)
{
// returns whether the input integer is even
return !($var & 1);
}
$str = "1-a,2-b,3-c";
$temp = preg_split("/(-|,)/", $str); // spliting with - and , as said multiple delim
$result =array_combine(array_filter($temp, "even", ARRAY_FILTER_USE_KEY),
array_filter($temp, "odd",ARRAY_FILTER_USE_KEY));
print_r($result);
array_filter — Filters elements of an array using a callback function
Note:- ARRAY_FILTER_USE_KEY - pass key as the only argument to callback instead of the value
array_combine — Creates an array by using one array for keys and another for its values
Demo
Output:-
Array
(
[1] => a
[2] => b
[3] => c
)
One way to do with array_map(),
<?php
$my_string = '1-a,2-b,3-c';
$my_array = array_map(function($val) {list($key,$value) = explode('-', $val); return [$key=>$value];}, explode(',', $my_string));
foreach(new RecursiveIteratorIterator(new RecursiveArrayIterator($my_array)) as $k=>$v){
$result[$k]=$v;
}
print_r($result);
?>
WORKING DEMO: https://3v4l.org/aYmOH
Tokens all the way down...
<?php
$str = '1-a,2-b,3-c';
$token = '-,';
if($n = strtok($str, $token))
$array[$n] = strtok($token);
while($n = strtok($token))
$array[$n] = strtok($token);
var_export($array);
Output:
array (
1 => 'a',
2 => 'b',
3 => 'c',
)
Or perhaps more terse without the first if...:
$array = [];
while($n = $array ? strtok($token) : strtok($str, $token))
$array[$n] = strtok($token);
Not a better way but one more example:
$str = "1-a,2-b,3-c";
$arr1 = explode(",", preg_replace("/\-([a-zA-Z]+)/", "", $str));
$arr2 = explode(",", preg_replace("/([0-9]+)\-/", "", $str));
print_r(array_combine($arr1, $arr2));
Mandatory one-liner (your mileage may vary):
<?php
parse_str(str_replace([',', '-'], ['&', '='], '1-a,2-b,3-c'), $output);
var_export($output);
Output:
array (
1 => 'a',
2 => 'b',
3 => 'c',
)
You can do one split on both the , and -, and then iterate through picking off every other pair ($k&1 is a check for an odd index):
<?php
$str = '1-a,2-b,3-c';
foreach(preg_split('/[,-]/', $str) as $k=>$v) {
$k&1 && $output[$last] = $v;
$last = $v;
}
var_export($output);
Output:
array (
1 => 'a',
2 => 'b',
3 => 'c',
)
The preg_split array looks like this:
array (
0 => '1',
1 => 'a',
2 => '2',
3 => 'b',
4 => '3',
5 => 'c',
)
This one explodes the string as the OP has on the comma, forming the pairs: (1-a) and (2-b) etc. and then explodes those pairs. Finally array_column is used to create the associated array:
<?php
$str = '1-a,2-b,3-c';
$output =
array_column(
array_map(
function($str) { return explode('-', $str); },
explode(',', $str)
),
1,
0
);
var_export($output);
Output:
array (
1 => 'a',
2 => 'b',
3 => 'c',
)

PHP array_unique is not returning unique values [duplicate]

My array is :
$array= array(4,3,4,3,1,2,1);
And I'd like to output it like below:
Output = 2
(As 2 is present only once)
This is what I've tried:
$array = array(4, 3, 4, 3, 1, 2, 1);
$array1 = array(4, 3, 4, 3, 1, 2, 1);
$array_diff = array_diff($array, $array1);
*Read last section of this an for the most stable technique the avoids fringe case issues -- it is also the most verbose.
One-liner with no loops: (Demo)
var_export(array_keys(array_intersect(array_count_values($array),[1])));
The breakdown:
array_keys( // return the remaining keys from array_count_values
array_intersect( // filter the first array by second
array_count_values($array), // count number of occurrences of each value
[1] // identify the number of occurrences to keep
)
)
if you (or any future reader) wants to keep more values, replace the second parameter/array in array_intersect().
for instance:
you want to keep 1,2,and 3: array(1,2,3) or [1,2,3]
p.s. For the record, you can use array_filter() with a custom function to omit all non-1 count values, but I have used array_intersect() because the syntax is more brief and IMO easier to read.
p.s. thought I'd revisit and include a PHP7.4 technique and compare against other function-based techniques...
Code: (Demo)
$numbers = [4, 3, 4, 3, 1, 2, 1];
var_export(
array_keys(
array_intersect(
array_count_values($numbers),
[1]
)
)
);
echo "\n---\n";
var_export(
array_keys(
array_filter(
array_count_values($numbers),
function($count) {
return $count === 1;
}
)
)
);
echo "\n---\n";
// PHP7.4+
var_export(
array_keys(
array_filter(
array_count_values($numbers),
fn($count) => $count === 1
)
)
);
*For similar tasks which have values which are not guaranteed to be integers, array_count_values() will complain with "Warning: array_count_values(): Can only count string and integer values".
Even a classic loop that uses values as first level keys like #LF00's answer will suffer potential side effects due to floats and numeric values being cast as integers automatically.
This means that a more general-use solution would be: (Demo)
$result = [];
foreach ($array as $index => $value) {
foreach ($array as $i => $v) {
if ($value === $v && $index !== $i) {
continue 2; // duplicate found, stop checking this value; do not retain
}
}
$result[] = $value;
}
var_export($result);
You could use the array_count_values() php function.
For example:
$numbers = [4, 3, 4, 3, 1, 2, 1];
// build count array as key = number and value = count
$counter_numbers = array_count_values($numbers);
print_r($counter_numbers);
Output :
Array
(
[4] => 2
[3] => 2
[1] => 2
[2] => 1
)
Then loop through the new array to get non-repeated values :
$unique_numbers = [];
foreach ($counter_numbers as $number => $count) {
if ($count === 1) {
$unique_numbers[] = $number;
}
}
print_r($unique_numbers);
Output :
Array
(
[0] => 2
)
You can do it like this: Count the occurrences of each element, then filter out the occurrences bigger than 1.
$array = [4, 3, 4, 3, 1, 2, 1];
foreach ($array as $v)
{
$arr[$v][] = 1; // doesn't matter if 1 is set to a different value
}
foreach($arr as $k => $v)
{
if (count($v) == 1) {
$o[] = $k;
}
}
print_r($o);
result:
Array
(
[0] => 2
)
If in your scenario there will be only one unique value you could use:
$array= array(4,3,4,3,1,2,1);
$singleValue = array_search(1, array_count_values($array));
var_dump($singleValue) // Outputs: 2

Find all array keys that has same value

Is there a simpler way to get all array keys that has same value, when the value is unknown.
The problem with array_unique is that it returns the unique array and thus it doesn't find unique values.
That is, for example, from this array:
Array (
[a]=>1000
[b]=>1
[c]=>1000
)
I want to get this
Array (
[a]=>1000
[c]=>1000
)
Another way around this is, if I could find the lonely values, and then their keys, and then use array_diff
This is what I've got so far, looks awful:
$a = array( 'a' => 1000, 'b' => 1, 'c' => 1000 );
$b = array_flip( array_count_values( $a ) );
krsort( $b );
$final = array_keys( $a, array_shift( $b ) );
Update
Using Paulo Freites' answer as a code base, I could get it working pretty easily, maintainable and easy on eyes kind of way… by using the filtering as a static class method I can get the duplicate values from an array by just calling ClassName::get_duplicates($array_to_filter)
private static $counts = null;
private static function filter_duplicates ($value) {
return self::$counts[ $value ] > 1;
}
public static function get_duplicates ($array) {
self::$counts = array_count_values( $array );
return array_filter( $array, 'ClassName::filter_duplicates' );
}
Taking advantage of closures for a more straightforward solution:
$array = array('a' => 1000, 'b' => 1, 'c' => 1000);
$counts = array_count_values($array);
$filtered = array_filter($array, function ($value) use ($counts) {
return $counts[$value] > 1;
});
var_dump($filtered);
This gave me the following:
array(2) {
["a"]=>
int(1000)
["c"]=>
int(1000)
}
Demo: https://eval.in/67526
That's all! :)
Update: backward-compatible solution
$array = array('a' => 1000, 'b' => 1, 'c' => 1000);
$counts = array_count_values($array);
$filtered = array_filter($array, create_function('$value',
'global $counts; return $counts[$value] > 1;'));
var_dump($filtered);
Demo: https://eval.in/68255
Your implementation has a few issues.
1) If there are 2 of value 1000 and 2 of another value, the array_flip will lose one of the sets of values.
2) If there are more than two different values, the array_keys will only find the one value that occurs most.
3) If there are no duplicates, you will still bring back one of the values.
Something like this works always and will return all duplicate values:
<?php
//the array
$a = array( 'a' => 1000, 'b' => 1, 'c' => 1000 );
//count of values
$cnt = array_count_values($a);
//a new array
$newArray = array();
//loop over existing array
foreach($a as $k=>$v){
//if the count for this value is more than 1 (meaning value has a duplicate)
if($cnt[$v] > 1){
//add to the new array
$newArray[$k] = $v;
}
}
print_r($newArray);
http://codepad.viper-7.com/fal5Yz
If you want to get the duplicates in an array try this:
array_unique(array_diff_assoc($array1, array_unique($array1)))
I found this from:
http://www.php.net/manual/en/function.array-unique.php#95203
at the moment I cant figure out another solution...
// target array
$your_array = array('a'=>1000, 'b'=>1, 'c'=>1000);
// function to do all the job
function get_duplicate_elements($array) {
$res = array();
$counts = array_count_values($array);
foreach ($counts as $id=>$count) {
if ($count > 1) {
$r = array();
$keys = array_keys($array, $id);
foreach ($keys as $k) $r[$k] = $id;
$res[] = $r;
}
}
return sizeof($res) > 0 ? $res : false;
}
// test it
print_r(get_duplicate_elements($your_array));
output:
Array
(
[0] => Array
(
[a] => 1000
[c] => 1000
)
)
example #2: - when you have different values multiplied
// target array
$your_array = array('a'=>1000, 'b'=>1, 'c'=>1000, 'd'=>500, 'e'=>1);
// output
print_r(get_duplicate_elements($your_array));
output:
Array
(
[0] => Array
(
[a] => 1000
[c] => 1000
)
[1] => Array
(
[b] => 1
[e] => 1
)
)
if function result has been assigned to $res variable $res[0] gets an array of all elements from original array with first value found more than once, $res[1] gets array of elements with another duplicated-value, etc... function returns false if nothing duplicate has been found in argument-array.
Try this
$a = array( 'a' => 1, 'b' => 1000, 'c' => 1000,'d'=>'duplicate','e'=>'duplicate','f'=>'ok','g'=>'ok' );
$b = array_map("unserialize", array_unique(array_map("serialize", $a)));
$c = array_diff_key($a, $b);
$array = array("1"=>"A","2"=>"A","3"=>"A","4"=>"B","5"=>"B","6"=>"B");
$val = array_unique(array_values($array));
foreach ($val As $v){
$dat[$v] = array_keys($array,$v);
}
print_r($dat);

Categories