comparing people in array - php

The problem I'm trying to solve is this.
I have an array of people, some of the people repeat in this array, but their details aren't always exactly the same, there are slight variations in their name. So what I'm trying to do is loop through all the names and compare how close the name is, then if that's a match compare their age and hometown.
Later I hope to create a new array and say "this person also has appears with the following ids" ...
What I have so far is a bubble sort, which if I let it run for long enough I'm sure I can get the job done. I'm just looking to see if someone has a better solution?
<?php
$arr = [
[
'id' => '123',
'name' => 'gary strange',
'home' => 'london',
'age' => 23
],
[
'id' => '124',
'name' => 'john jones',
'home' => 'london',
'age' => 45
],
[
'id' => '125',
'name' => 'bob smith',
'home' => 'paris',
'age' => 63
],
[
'id' => '126',
'name' => 'g strange',
'home' => 'london',
'age' => 23
],
[
'id' => '127',
'name' => 'gary strange',
'home' => 'paris',
'age' => 23
],
[
'id' => '128',
'name' => 'g f. strange',
'home' => 'london',
'age' => 23
]
];
for($i = 0; $i < count($arr); $i++) {
echo "Getting details for " . $arr[$i]['name'] . "\n";
for($j = 0; $j < count($arr); $j++) {
if($j == $i) continue;
else{
echo "Comparing to " . $arr[$j]['name'];
$str1 = $arr[$i]['name'];
$str2 = $arr[$j]['name'];
similar_text($str1,$str2,$percent);
echo " - " . $percent . "%\n";
}
}
echo "******\n";
}

It would probably be more efficient to compare only against people who have a similar age and hometown, and THEN do your comparison checks on name. Comparing against everyone first seems to be like it would be extraordinarily slow.
Something like this for your SQL, as you're iterating through each user:
SELECT name, age, hometown
FROM users
WHERE age BETWEEN value1 AND value2
AND hometown LIKE value3
And THEN do your comparison check. Make sure you use iterators -- this will keep your memory management at bay if you're iterating through tens of thousands of people.
This way, for each user, you're probably only comparing against a handful of possible matches (instead of potentially thousands).

Related

How can I manage some irregular array to regular array?

I write code with some array that have different structure, but I must extract the data to do something else. How can I manager these array?
The array's structure are as follow:
$a = [
'pos1' => 'somedata',
'pos2' => ['data2', 'data3'],
'pos3' => '';
];
$b = [
[
'pos1' => ['data1', 'data2', ['nest1', 'nest2']],
'pos2' => ['data1', 'data2', 'data3'],
],
['data1', 'data2'],
'data4',
];
The array's Index can be a key or a position, and the value of the corresponding index may be a array with the same structure. More tough problem is that the subarray can be nesting, and the time of the nesting has different length.
Fortunately, every array has it's owe fixed structure.
I want to convert the these array to the format as follow. When the index is a value, change it to the keyword; and if the index is a keyword, nothing changed.
$a = [
'pos1' => 'somedata',
'pos2' => [
'pos2_1' => 'data2',
'pos2_2' => 'data3'
],
'pos3' => '';
];
$b = [
'pos1' => [
'pos1_1' => [
'pos1_1_1' => 'data1',
'pos1_1_2' => 'data2',
'pos1_1_3' => [
'pos1_1_3_1' => 'nest1',
'pos1_1_3_2' => 'nest2',
],
],
'pos1_2' => [
'pos1_2_1' => 'data1',
'pos1_2_2' => 'data2',
'pos1_2_3' => 'data3',
],
],
'pos2' => ['data1', 'data2'],
'pos3' => 'data4',
];
My first solution is for every array, write the function to convert the format(the keyword will specify in function). But it is a huge task and diffcult to manage.
The second solution is write a common function, with two argument: the source array and the configuration that specify the keyword to correspondent value index. For example:
$a = [0, ['pos10' => 1]];
$conf = [
// It means that when the value index is 0, it will change it into 'pos1'
'pos1' => 0,
'pos2' => 1,
];
The common funciton will generate the result of:
$result = [
'pos1' => 0,
'pos2' => ['pos10' => 1],
]
But this solution will lead to a problem: the config is diffcult to understand and design, and other people will spend a lot of time to understand the format after conversion.
Is there are some better solution to manage these array that other people can easy to use these array?
Thanks.

Create Main Array that includes multiple child array

How Can I Create a main array that includes multiple child array And be in the form of Jason and I want to add the child Array to main array in the Loop
MainArray=[
array1=[{fname:asdada,lastname:sdsadasda}];
array2=[{fname:asdada,lastname:sdsadasda}];
array3=[{fname:asdada,lastname:sdsadasda}];
];
echo MainArray[1]->fname;
Please see the following pseudo code below:
pseudo code
You should really look into a basic php tutorial.
This is how you do it.
$mainArray = [
'array1' => ['fname' => 'asdada', 'lastname' => 'sdsadasda'],
'array2' => ['fname' => 'asdada', 'lastname' => 'sdsadasda'],
'array3' => ['fname' => 'asdada', 'lastname' => 'sdsadasda']
];
echo $mainArray['array1']['fname'];
Or use the long notation if you have an older version of php or want backwards compatibility.
$mainArray = array(
'array1' => array('fname' => 'foo', 'lastname' => 'bar'),
'array2' => array('fname' => 'lorem', 'lastname' => 'ipsum'),
'array3' => array('fname' => 'test', 'lastname' => 'example')
);
echo $mainArray['array1']['fname'];
Explanation:
The php variable sigil is $. This means that in order to access a variable or assign something to a variable, you use $mainArray. See more on variables in the documentation.
The php array can be used in two different notations. Either array(...) or, from php 5.4 upwards, [...]. Other than the opening and closing parts, they are identical. You don't use : or = to assign individual values inside an array declaration. For this you use the => operator. Each element in an array is separated by a comma (,).
E.g.
$mainArray = array(
'A' => 1,
'B' => 2
];
Arrays in Php can be either associative or numerical. What you probably want is that your outer array is numerical, meaning you can access it using $mainArray[1], and your inner array is associative. For numerical arrays, you don't specify a key yourself, so there is no need for the =>.
$mainArray = array(
array(),
array(),
array()
);
And with associative sub arrays this becomes:
$mainArray = array(
array('firstname' => 'foo', 'lastname' => 'bar'),
array('firstname' => 'test', 'lastname' => 'example'),
array('firstname' => 'lorem', 'lastname' => 'ipsum')
);
In order to access the firstname key of the first child array in this multilevel array structure, you do:
$mainArray[0]['firstname']
E.g. (if you want to echo it to the standard output)
echo $mainArray[0]['firstname'];
Please note that numerical arrays in php start counting on 0, as in most other programming languages. And please note that the key in the associative array is a string, and as such must be surrounded with either ' or ".
I can recommend you search for a php beginner's tutorial and try to write and execute the examples yourself, to get a better grasp of php. If you need somewhere to run your php examples, I can recommend you try an online php environment such as PHPFiddle.
Update on adding values:
You can add more key=>value pairs to an associative array or add more values to a numerical array afterwards in much the same way as you would access or assign to it.
First, let's add a value to a numerical array. You do this by adding [] to the end of your variable when assigning. This means that what you assign will be added as a new numerical value to the end of your array.
$numericalArray = array(
7,
8,
6,
12,
'B'
);
$numericalArray[] = 'C';
// Results in the array: array(7, 8, 6, 12, 'B', 'C')
And in order to add a new key => value pair to an associative array, you just add it using the new key, e.g.
$assoc = array(
'firstname' => 'Testy',
'lastname' => 'McTestface'
);
$assoc['middlename'] => 'Tester';
So to add a new fname-lastname pair to the mainArray, you would do:
$mainArray = array(
array('fname' => 'foo', 'lastname' => 'bar'),
array('fname' => 'test', 'lastname' => 'example'),
array('fname' => 'lorem', 'lastname' => 'ipsum')
);
$mainArray[] = array('fname' => 'new name', 'lastname' => 'new last name');
If you want to do this in a loop, you will use the for, foreach, while or do while structures.
E.g.
$mainArray = array(
array('fname' => 'foo', 'lastname' => 'bar'),
array('fname' => 'test', 'lastname' => 'example'),
array('fname' => 'lorem', 'lastname' => 'ipsum')
);
for ($i = 0; $i < 3; ++$i) {
$mainArray[] = array('fname' => 'new name ' . $i, 'lastname' => 'new last name ' . $i);
}
echo json_encode($mainArray, JSON_PRETTY_PRINT|JSON_UNESPACED_UNICODE|JSON_UNESCAPED_SLASHES), PHP_EOL;
// [
// {'fname': 'foo', 'lastname': 'bar'},
// {'fname': 'test', 'lastname': 'example'},
// {'fname': 'lorem', 'lastname': 'ipsum'},
// {'fname': 'new name 0', 'lastname': 'new last name 0'},
// {'fname': 'new name 1', 'lastname': 'new last name 1'},
// {'fname': 'new name 2', 'lastname': 'new last name 2'},
// ]

Keep array rows where a column value is found in a second flat array

** I have edited this to show how I got my code to work using array_search
I have an array, $arr1 with 5 columns as such:
key id name style age whim
0 14 bob big 33 no
1 72 jill big 22 yes
2 39 sue yes 111 yes
3 994 lucy small 23 no
4 15 sis med 24 no
5 16 maj med 87 yes
6 879 Ike larg 56 no
7 286 Jed big 23 yes
This array is in a cache, not a database.
I then have a second array with a list of id values -
$arr2 = array(0=>14, 1=>72, 2=>8790)
How do I filter $arr1 so it returns only the rows with the id values in $arr2?
I got my code to work as follows:
$arr1 = new CachedStuff(); // get cache
$resultingArray = []; // create an empty array to hold rows
$filter_function = function ($row) use ($arr2) {
return (array_search($row['id'], $arr2));
};
$resultingArrayIDs = $arr1->GetIds($filter_function, $resultingArray);
This gives me two outputs: $resultingArray & $resultingArrayIDs both of which represent the intersection of the $arr1 and $arr2.
This whole task can be accomplished with just one slick, native function call -- array_uintersect().
Because the two compared parameters in the custom callback may come either input array, try to access from the id column and if there isn't one declered, then fallback to the parameter's value.
Under the hood, this function performs sorting while evaluating as a means to improve execution time / processing speed. I expect this approach to outperform iterated calls of in_array() purely from a point of minimized function calls.
Code: (Demo)
var_export(
array_uintersect(
$arr1,
$arr2,
fn($a, $b) =>
($a['id'] ?? $a)
<=>
($b['id'] ?? $b)
)
);
Something like this should do it, provided I've understood your question and data structure correctly:
$dataArray = [
[ 'key' => 0, 'id' => 14 , 'name' => 'bob' , 'style' => 'big' , 'age' => 33 , 'whim' => 'no' ],
[ 'key' => 1, 'id' => 72 , 'name' => 'jill' , 'style' => 'big' , 'age' => 22 , 'whim' => 'yes' ],
[ 'key' => 2, 'id' => 39 , 'name' => 'sue' , 'style' => 'yes' , 'age' => 111 , 'whim' => 'yes' ],
[ 'key' => 3, 'id' => 994 , 'name' => 'lucy' , 'style' => 'small' , 'age' => 23 , 'whim' => 'no' ],
[ 'key' => 4, 'id' => 15 , 'name' => 'sis' , 'style' => 'med' , 'age' => 24 , 'whim' => 'no' ],
[ 'key' => 5, 'id' => 16 , 'name' => 'maj' , 'style' => 'med' , 'age' => 87 , 'whim' => 'yes' ],
[ 'key' => 6, 'id' => 879 , 'name' => 'Ike' , 'style' => 'larg' , 'age' => 56 , 'whim' => 'no' ],
[ 'key' => 7, 'id' => 286 , 'name' => 'Jed' , 'style' => 'big' , 'age' => 23 , 'whim' => 'yes' ]
];
$filterArray = [14, 72, 879];
$resultArray = array_filter( $dataArray, function( $row ) use ( $filterArray ) {
return in_array( $row[ 'id' ], $filterArray );
} );
View this example on eval.in
However, your question appears to suggest this data might be coming from a database; is that correct? If so, perhaps it's more efficient to pre-filter the results at the database-level. Either by adding a field in the SELECT query, that represents a boolean value whether a row matched your filter ids, or by simply not returning the other rows at all.
One way is with foreach loop with array_search()
$result = [];
foreach ($arr1 as $value) { // Loop thru $arr1
if (array_search($value['id'], $arr2) !== false) { // Check if id is in $arr2
$result[] = $value; // Push to result if true
}
}
// print result
print_r($result);
As #DecentDabbler mentioned - if the data is coming out of a database, using an IN on your WHERE will allow you to retrieve only the relevant data.
Another way to filter is to use array functions
array_column extracts the value of the id column into an array
array_intersect returns the elements which are in both $arr1['id'] and $arr2
array_flip flips the resulting array such that the indices into $arr1 indicate the elements in both $arr1 and $arr2
$arr1 = [ [ 'id' => 14, 'name' => 'bob'],
['id' => 72, 'name' => 'jill'],
['id' => 39, 'name' => 'sue'],
['id' => 994, 'name' => 'lucy'],
['id' => 879, 'name'=> 'large']];
$arr2 = [ 14,72,879 ];
$intersection = array_flip(array_intersect(array_column($arr1,'id'),$arr2));
foreach ($intersection as $i) {
var_dump($arr1[$i]);;
}

Find combinations of a two dimensional array

I need some help with generation of combinations, specifically in the store they're the variants of each product, e.g size and colour.
Let's say we have 3 customizable properties of the product:
Colour, Size, and Type.
For this specific product, the following are available of each property:
Color: [red, green], Size: [10, 11, 15], Type: [person]
Now according to the above data, I need to generate 6 combinations, however if we added another type it would increase even more.
I have been drawing on my board for 2 hours now trying to come up with a sane algorithm for this, something that's fast and can deal with thousands of combinations in a matter of seconds.
Take this example:
$options = ['Color' => ['Red', 'Green'], 'Size' => ['10', '11', '15'], 'Type' => ['person']];
$combinations = generateCombinations($options);
genereateCombinations would then need to generate the following output:
[
['Color' => 'Red', 'Size' => '10', 'Type' => 'person'],
['Color' => 'Red', 'Size' => '11', 'Type' => 'person'],
['Color' => 'Red', 'Size' => '15', 'Type' => 'person'],
['Color' => 'Green', 'Size' => '10', 'Type' => 'person'],
['Color' => 'Green', 'Size' => '11', 'Type' => 'person'],
['Color' => 'Green', 'Size' => '15', 'Type' => 'person']
];
What algorithm could do this efficiently and with unlimited input "titles"? (of course I'll enforce a limit earlier, but the algorithm should be able to do unlimited granted all the resources in the world)
Extending what I mean:
This function also needs to be able to take for example an array with 100 property rows, not just 3, it needs to be able to do this dynamically no matter the number of input rows.
Three foreach loops are enough to generate all combinations, no matter how many entries are in $options:
function generateCombinations(array $options)
{
// Start with one combination of length zero
$all = array(array());
// On each iteration append all possible values of the new key
// to all items in $all; generate this way all the combinations
// one item longer than before
foreach ($options as $key => $values) {
// Move all combinations of length N from $all to $current
$current = $all;
// Start with an empty list of combinations of length N+1
$all = array();
// Combine each combination of length N
// with all possible values for the (N+1)th key
foreach ($current as $one) {
foreach ($values as $val) {
// Put each new combination in $all (length N+1)
$all[] = array_merge($one, array($key => $val));
}
}
}
return $all;
}
$options = [
'Color' => ['Red', 'Green'],
'Size' => ['10', '11', '15'],
'Type' => ['person'],
'Answer' => ['Yes', 'No'],
];
$combinations = generateCombinations($options);
echo(count($combinations));
# 12
It can probably be slightly improved but, all in all, if you don't know in advance the length of $options it does a lot of duplicate iterations. If you know in advance the number of items in $options (let's say it is N) then N nested loops are the fast way to do it.

Count specific rows

I am using bootstrap progress bar to display stats.
I want to know how many scored 10 points out of total no of rows.
$q="SELECT * FROM users";
$r = mysqli_query($con,$q);
$total = mysqli_num_rows($r);
Name email score time
Hello abc#gmail.com 10 15
Hello abc#gmail.com 58 10
Test def#gmail.com 10 12
Stack xyz#gmail.com 90 20
Test def#gmail.com 50 40
$q="SELECT COUNT(Name) FROM users WHERE score='10' ";
You can use this simple query to get it done :-
SELECT COUNT(name), score
FROM users
GROUP BY score
This would get the total for each individual score (10,9,8).
If you want total only for value 10. Use this instead.
SELECT COUNT(name), score
FROM users
WHERE score=10
This will loop through the $total array and assign all the values less than 10 into an array then loop through that array to print out how many out of total for each less than 10.
$total = [
0 => [
'name' => 'Hello',
'email' => 'abc#gmail.com',
'score' => 10,
'time' => 15
],
1 => [
'name' => 'Hello',
'email' => 'abc#gmail.com',
'score' => 58,
'time' => 10
],
2 => [
'name' => 'Test',
'email' => 'def#gmail.com',
'score' => 10,
'time' => 12
],
3 => [
'name' => 'Stack',
'email' => 'xyz#gmail.com',
'score' => 90,
'time' => 20
],
4 => [
'name' => 'Test',
'email' => 'def#gmail.com',
'score' => 50,
'time' => 40
],
];
$sizeOfArray = count($total);
$arrayOfScoresLessThanTen = [];
foreach($total as $value) {
if($value['score'] <= 10) {
if(isset($arrayOfScoresLessThanTen[$value['score']])) {
$arrayOfScoresLessThanTen[$value['score']] ++;
}
else {
$arrayOfScoresLessThanTen[$value['score']] = 1;
}
}
}
foreach($arrayOfScoresLessThanTen as $key => $scoresLessThanTen) {
echo 'Score: '. $key . ' number scored out of total: '. $scoresLessThanTen . '/'.$sizeOfArray;
}
This has been tested and works with the array $total that I created to match the one you had in your table. I added my $total array so that you can test it for yourself.

Categories