Finding frequent sequence of numbers in an array - php

Array (3, 5, 1, 3, 5, 48, 4, 7, 13, 55, 65, 4, 7, 13, 32)
the frequent sequence of numbers will be (3, 5) f=2 + (4, 7, 13) f=2
any Algorithm or Pseudo code to find that ?
Update(1):
if (7, 13) also occurrence it will be included in the longest one by update its frequency so
(4, 7, 13) f=3 and so on...
Update(2):
in case of (1,2,3,4,1,2,3,4,1,2,7,8,7,8,3,4,3,4,1,2) the output should be (1,2,3,4) & (3,4,1,2)
& (7,8) , to make it clear consider each number as a word and you want to find most frequent phrases
so it is common to see same word(s) in a lot of phrases but if any phrase was sub-string for any other
phrase(s) should not be consider as a phrase but will update frequency of each phrase includes it

** EDIT ** : slightly better implementation, now also returns frequences and has a better sequence filter.
function getFrequences($input, $minimalSequenceSize = 2) {
$sequences = array();
$frequences = array();
$len = count($input);
for ($i=0; $i<$len; $i++) {
$offset = $i;
for ($j=$i+$minimalSequenceSize; $j<$len; $j++) {
if ($input[$offset] == $input[$j]) {
$sequenceSize = 1;
$sequence = array($input[$offset]);
while (($offset + $sequenceSize < $j)
&& ($input[$offset+$sequenceSize] == $input[$j+$sequenceSize])) {
if (false !== ($seqIndex = array_search($sequence, $frequences))) {
// we already have this sequence, since we found a bigger one, remove the old one
array_splice($sequences, $seqIndex, 1);
array_splice($frequences, $seqIndex, 1);
}
$sequence[] = $input[$offset+$sequenceSize];
$sequenceSize++;
}
if ($sequenceSize >= $minimalSequenceSize) {
if (false !== ($seqIndex = array_search($sequence, $sequences))) {
$frequences[$seqIndex]++;
} else {
$sequences[] = $sequence;
$frequences[] = 2; // we have two occurances already
}
// $i += $sequenceSize; // move $i so we don't reuse the same sub-sequence
break;
}
}
}
}
// remove sequences that are sub-sequence of another frequence
// ** comment this to keep all sequences regardless **
$len = count($sequences);
for ($i=0; $i<$len; $i++) {
$freq_i = $sequences[$i];
for ($j=$i+1; $j<$len; $j++) {
$freq_j = $sequences[$j];
$freq_inter = array_intersect($freq_i, $freq_j);
if (count($freq_inter) != 0) {
$len--;
if (count($freq_i) > count($freq_j)) {
array_splice($sequences, $j, 1);
array_splice($frequences, $j, 1);
$j--;
} else {
array_splice($sequences, $i, 1);
array_splice($frequences, $i, 1);
$i--;
break;
}
}
}
}
return array($sequences, $frequences);
};
Test case
header('Content-type: text/plain');
$input = array(3, 5, 1, 3, 5, 48, 4, 7, 13, 55, 3, 5, 65, 4, 7, 13, 32, 5, 48, 4, 7, 13);
list($sequences, $frequences) = getFrequences($input);
foreach ($sequences as $i => $s) {
echo "(" . implode(',', $s) . ') f=' . $frequences[$i] . "\n";
}
** EDIT ** : here's an update to the function. It was almost completely rewritten... tell me if this is what you were looking for. I also added a redundancy check to prevent counting the same sequence, or subsequence, twice.
function getFrequences2($input, $minSequenceSize = 2) {
$sequences = array();
$last_offset = 0;
$last_offset_len = 0;
$len = count($input);
for ($i=0; $i<$len; $i++) {
for ($j=$i+$minSequenceSize; $j<$len; $j++) {
if ($input[$i] == $input[$j]) {
$offset = 1;
$sub = array($input[$i]);
while ($i + $offset < $j && $j + $offset < $len) {
if ($input[$i + $offset] == $input[$j + $offset]) {
array_push($sub, $input[$i + $offset]);
} else {
break;
}
$offset++;
}
$sub_len = count($sub);
if ($sub_len >= $minSequenceSize) {
// $sub must contain more elements than the last sequence found
// otherwise we will count the same sequence twice
if ($last_offset + $last_offset_len >= $i + $sub_len) {
// we already saw this sequence... ignore
continue;
} else {
// save offset and sub_len for future check
$last_offset = $i;
$last_offset_len = $sub_len;
}
foreach ($sequences as & $sequence) {
$sequence_len = count($sequence['values']);
if ($sequence_len == $sub_len && $sequence['values'] == $sub) {
//echo "Found add-full ".var_export($sub, true)." at $i and $j...\n";
$sequence['frequence']++;
break 2;
} else {
if ($sequence_len > $sub_len) {
$end = $sequence_len - $sub_len;
$values = $sequence['values'];
$slice_len = $sub_len;
$test = $sub;
} else {
$end = $sub_len - $sequence_len;
$values = $sub;
$slice_len = $sequence_len;
$test = $sequence['values'];
}
for ($k=0; $k<=$end; $k++) {
if (array_slice($values, $k, $slice_len) == $test) {
//echo "Found add-part ".implode(',',$sub)." which is part of ".implode(',',$values)." at $i and $j...\n";
$sequence['values'] = $values;
$sequence['frequence']++;
break 3;
}
}
}
}
//echo "Found new ".implode(',',$sub)." at $i and $j...\n";
array_push($sequences, array('values' => $sub, 'frequence' => 2));
break;
}
}
}
}
return $sequences;
};

In Python3
>>> from collections import Counter
>>> count_hash=Counter()
>>> T=(3, 5, 1, 3, 5, 48, 4, 7, 13, 55, 65, 4, 7, 13, 32)
>>> for i in range(2,len(T)+1):
... for j in range(len(T)+1-i):
... count_hash[T[j:j+i]]+=1
...
>>> for k,v in count_hash.items():
... if v >= 2:
... print(k,v)
...
(3, 5) 2
(4, 7, 13) 2
(7, 13) 2
(4, 7) 2
Do you need to filter the (7,13) and the (4,7) out? What happens if there was also (99, 7, 14) in the sequence?
a Counter is just like a hash used to keep track of the number of times we see each substring
The two nested for loops produce all the substrings of T, using count_hash to accumulate the count of each substring.
The final for loop filters all those substrings that only occurred once
Here is a version with a filter
from collections import Counter
def substrings(t, minlen=2):
tlen = len(t)
return (t[j:j+i] for i in range(minlen, tlen+1) for j in range(tlen+1-i))
def get_freq(*t):
counter = Counter(substrings(t))
for k in sorted(counter, key=len):
v=counter[k]
if v < 2:
del counter[k]
continue
for t in substrings(k):
if t in counter:
if t==k:
continue
counter[k]+=counter[t]-v
del counter[t]
return counter
print(get_freq(3, 5, 1, 3, 5, 48, 4, 7, 13, 55, 65, 4, 7, 13, 32, 4, 7))
print(get_freq(1,2,3,4,1,2,3,4,1,2,7,8,7,8,3,4,3,4,1,2))
the output is
Counter({(4, 7, 13): 3, (3, 5): 2})
Counter({(1, 2, 3, 4, 1, 2): 8, (7, 8): 2}) # Is this the right answer?
Which is why I asked how the filtering should work for the sequence I gave in the comments

Ok, just to start off the discussion.
Create another array/map, call this
weightage array.
Start iterating on the values array.
For each value in
values array,increment the
corresponding position in weightage
array. Eg: for 3 increase
weightage[3]++, for 48
weightage[48]++.
After the iteration the weightage array contains
repetitions

Related

Function to find closest value or closest sum value of elements to given number

I want to send an integer array and a number to function and function will give me closest element or element sum to my number.
for example: our funtion name is findclosestsum.
findClosestSum([2, 3, 7, 14, 15], 25) --> must give 3,7,15 because sum of this 3 element is exactly 25.
findClosestSum([2, 3, 7, 14, 15], 15) --> must give only 15
findClosestSum([2, 3, 7, 14, 15], 11) --> must give 3,7 because sum=10 and very closer to 11
here is my php code
function findClosestSum($array, $number) {
$result = [];
$minDiff = null;
$arrayCount = count($array);
for ($i = 0; $i < $arrayCount; $i++) {
for ($j = $i + 1; $j < $arrayCount; $j++) {
$sum = $array[$i] + $array[$j];
$diff = abs($number - $sum);
if ($sum == $number) {
return [$array[$i], $array[$j]];
} elseif ($minDiff === null || $diff < $minDiff) {
$minDiff = $diff;
$result = [$array[$i], $array[$j]];
}
}
}
return $result;
}
it returns 7 and 15 for findClosestSum([2, 3, 7, 14, 15], 25). where is my mistake?
For solving this problem in a more productive and precise result, you may need to implement this with graphs.

What's wrong with my semi complete Sudoku solver?

I'm trying to practice algorithm questions and I'm currently attempting a sudoku solver, please bare in mind that it isn't currently finished! I haven't added backtracking when there is more than one option that the cell could be, but my issue currently is that my if statement to check if there is only one possible answer the cell could be is failing, as the semi filled sudoku its returning is wrong.
Also feel free to give me tips on how to speed things up etc.
function sudoku(array $puzzle): array
{
// Return the solved puzzle as a 9 × 9 grid
$data = [];
for ($i = 0; $i < 8; $i++) {
for ($a = 0; $a < 8; $a++) {
if ($puzzle[$i][$a] == 0) {
$horizontal_missing = getHorizontalNumbers($puzzle[$i]);
$vertical_missing = getVerticalNumbers($puzzle, $a);
$square_missing = getSquareNumbers($puzzle, $i, $a);
$intersect = array_intersect($horizontal_missing,$vertical_missing,$square_missing);
if (count($intersect) == 1) {
sort($intersect);
$puzzle[$i][$a] = $intersect[0];
$i = 0;
$a = 0;
}
}
}
}
return $puzzle;
}
function getSquareNumbers($p, $row, $col)
{
$sectors = [1 => [0, 2], 2 => [3, 5], 3 => [6, 8]];
$across = getSector($sectors, $row);
$down = getSector($sectors, $col);
switch (($across * $down)) {
case 1:
$row = [
$p[0][0], $p[0][1], $p[0][2],
$p[1][0], $p[1][1], $p[1][2],
$p[2][0], $p[2][1], $p[2][2]
];
break;
case 2:
$row = [
$p[0][3], $p[0][4], $p[0][5],
$p[1][3], $p[1][4], $p[1][5],
$p[2][3], $p[2][4], $p[2][5]
];
break;
case 3:
$row = [
$p[0][6], $p[0][7], $p[0][8],
$p[1][6], $p[1][7], $p[1][8],
$p[2][6], $p[2][7], $p[2][8]
];
break;
case 4:
$row = [
$p[3][0], $p[3][1], $p[3][2],
$p[4][0], $p[4][1], $p[4][2],
$p[5][0], $p[5][1], $p[5][2]
];
break;
case 5:
$row = [
$p[3][3], $p[3][4], $p[3][5],
$p[4][3], $p[4][4], $p[4][5],
$p[5][3], $p[5][4], $p[5][5]
];
break;
case 6:
$row = [
$p[3][6], $p[3][7], $p[3][8],
$p[4][6], $p[4][7], $p[4][8],
$p[5][6], $p[5][7], $p[5][8]
];
break;
case 7:
$row = [
$p[6][0], $p[6][1], $p[6][2],
$p[7][0], $p[7][1], $p[7][2],
$p[8][0], $p[8][1], $p[8][2]
];
break;
case 8:
$row = [
$p[6][3], $p[6][4], $p[6][5],
$p[7][3], $p[7][4], $p[7][5],
$p[8][3], $p[8][4], $p[8][5]
];
break;
case 9:
$row = [
$p[6][6], $p[6][7], $p[6][8],
$p[7][6], $p[7][7], $p[7][8],
$p[8][6], $p[8][7], $p[8][8]
];
break;
}
return getHorizontalNumbers($row);
}
function getSector($sectors, $num)
{
if (($sectors[1][0] <= $num) && ($num <= $sectors[1][1])) {
return 1;
} else if (($sectors[2][0] <= $num) && ($num <= $sectors[2][1])) {
return 2;
} else if (($sectors[3][0] <= $num) && ($num <= $sectors[3][1])) {
return 3;
}
}
function getHorizontalNumbers($row)
{
$missing = [];
for ($i = 1; $i <= 9; $i++) {
if (!in_array($i, $row)) {
$missing[] = $i;
}
}
return $missing;
}
function getVerticalNumbers($puzzle, $col)
{
$row = [
$puzzle[0][$col],
$puzzle[1][$col],
$puzzle[2][$col],
$puzzle[3][$col],
$puzzle[4][$col],
$puzzle[5][$col],
$puzzle[6][$col],
$puzzle[7][$col],
$puzzle[8][$col]
];
return getHorizontalNumbers($row);
}
$data = sudoku([
[5, 3, 0, 0, 7, 0, 0, 0, 0],
[6, 0, 0, 1, 9, 5, 0, 0, 0],
[0, 9, 8, 0, 0, 0, 0, 6, 0],
[8, 0, 0, 0, 6, 0, 0, 0, 3],
[4, 0, 0, 8, 0, 3, 0, 0, 1],
[7, 0, 0, 0, 2, 0, 0, 0, 6],
[0, 6, 0, 0, 0, 0, 2, 8, 0],
[0, 0, 0, 4, 1, 9, 0, 0, 5],
[0, 0, 0, 0, 8, 0, 0, 7, 9]
]);
$string = '';
$count = 0;
foreach($data as $key => $row){
foreach($row as $cell){
$count++;
if ($count == 9){
$string.= $cell.", \n";
$count = 0;
} else {
$string.= $cell.", ";
}
}
}
echo nl2br($string);
Surely if I'm only inputting numbers where there is only ONE common denominator between vertical line, horizontal line and the square there shouldn't be any errors in the SEMI filled Sudoku so far, yet there is? What am I missing? My brain can't compute lol.
function test_sectors($puzzle=null) {
if (!$puzzle) {
$puzzle = [
[1,1,1, 2,2,2, 3,3,3],
[1,1,1, 2,2,2, 3,3,3],
[1,1,1, 2,2,2, 3,3,3],
[4,4,4, 5,5,5, 6,6,6],
[4,4,4, 5,5,5, 6,6,6],
[4,4,4, 5,5,5, 6,6,6],
[7,7,7, 8,8,8, 9,9,9],
[7,7,7, 8,8,8, 9,9,9],
[7,7,7, 8,8,8, 9,9,9]
];
}
for ($i=0; $i<9; $i++) {
for ($j=0; $j<9; $j++) {
$expected = $puzzle[$i][$j];
$sector = getSquareNumbers($puzzle, $i, $j);
if ($sector[0] == $expected) {
echo ".";
} else {
echo "F (got sector {$sector[0]} expected {$expected} at coord [{$i}][{$j}])\n";
};
}
}
}
test_sectors();
I did this function (I do not have a php at hand now) to test the behaviour of your getSquareNumbers function that seems odd to me. You can use it to see if the correct square is selected for every possible coordinate, you can automate it too (but it is up to you).
Edit:
Rewritten a la unit test fashion!
In getSquareNumbers you assume that $across * $down gives unique values, but that is not true:
For example 1*3 is 3, but also 3*1 is 1. Furthermore, there is no case where the product is 5, 7 or 8. So in many cases your code is looking at the wrong square area.
You can avoid a lot of code (duplication) by just using the modulo operator and slice the rows of the grid at given indices.
Secondly, you seem to swap the meaning of $down and $across. The first should be about rows and the second about columns, and the code does relates them differently.
Here is the suggested fix for that function:
function getSquareNumbers($p, $row, $col)
{
$down = $row - $row % 3; // This will be 0, 3 or 6
$across = $col - $col % 3; // This will be 0, 3 or 6
$row = [...array_slice($p[$down+0], $across, $across + 3),
...array_slice($p[$down+1], $across, $across + 3),
...array_slice($p[$down+2], $across, $across + 3)];
return getHorizontalNumbers($row);
}
Now your grid will be filled more... still leaving some zeroes, but those zeroes really represent cells that cannot be solved as there is no value that can be put there without violating one of the rules. So this is where you need to implement backtracking to continue the process in an alternative direction.

PHP Find a pair of elements from an array whose sum equals a given number

I have an array with n numbers from -10 to 10 (without 0). Implement function which returns quantity of pairs from the array which sum gives 0.
For example:
$input = array (3, 6, -3, 5, -10, 3, 10, 1, 7, -1, -9, -8, 7, 7, -7, -2, -7);
The right answer is 5 (pairs are bolded)
I made something like this but it gives me 10 pairs:
$length = count($input) - 1;
$count = 0;
for ($i = 0; $i <= $length; $i++) {
for ($j = $i + 1; $j <= $length; $j++) {
if ($input[$i] + $input[$j] == 0) {
$count++;
}
}
}
echo $count;
<?php
$input = array (3, 6, -3, 5, -10, 3, 10, 1, 7, -1, -9, -8, 7, 7, -7, -2, -7);
$length = count($input) - 1;
$count = 0;
for ($i = 0; $i <= $length; $i++){
$flag[$i]=0;
}
for ($i = 0; $i <= $length; $i++) {
for ($j = $i + 1; $j <= $length; $j++) {
if ($input[$i] + $input[$j] == 0 && $flag[$i]==0 && $flag[$j]==0) {
$count++;
$flag[$i]=1;
$flag[$j]=1;
}
}
}
echo $count;
?>
The correct code is given above. Since you have to mark the elements which are already used in making pair. For example, you have two +3 and one -3, which makes 2 pairs since you didn't mark it, that it has already made a pair with existing one.
You did two for loops, so you are counting the pairs twice. You can do some test, every input array you insert in the function will return an even number. Then do $count = $count/2; at final.
You need to define why its not working - it is but its finding 7 + -7 6 times: So you need to flag that this match has been found like the below code - with some added output so you can see what is happening:
$input = array (3, 6, -3, 5, -10, 3, 10, 1, 7, -1, -9, -8, 7, 7, -7, -2, -7);
$length = count($input) - 1;
$count = 0;
$matched = array();
for ($i = 0; $i < count($input); $i++) {
echo "<br />Group ".$i.": <strong>".$input[$i]."</strong>, ";
$groupmatch = 0;
$matchon = "";
for ($j = $i + 1; $j < count($input); $j++) {
echo $input[$j].", ";
$check = $input[$i] ."+". $input[$j];
if ($input[$i] + $input[$j] == 0 && !array_search($check,$matched)) {
$count++;
$groupmatch++;
$matchon .= $check.", ";
array_push($matched, $check);
}
}
echo "<br />Groupmatch: ".$groupmatch."<br/>";
echo $matchon."<br />";
}
echo $count;

PHP MD5 Implementation does not produce the correct result

I've been attempting to implement the MD5 hashing Algorithm in PHP and I have produced the code below. However, when I run the function with the test input "test", it produces the string "21aa63b9882532cd590623dbd8f2fa225350d682" as opposed to the expected "098f6bcd4621d373cade4e832627b4f6".
I have completely run out of ideas as to why this is returning an error, and would be extremely grateful if someone were to assist me.
Edit: I'm not using this in production, but rather in a school project.
My code:
<?php
/**
* Created by PhpStorm.
* User: Sam Gunner
* Date: 25/01/2017
* Time: 18:37
*/
class md5
{
private $k;
private $s;
//Constants as defined by the specification
private $a0 = 0x67452301;
private $b0 = 0xefcdab89;
private $c0 = 0x98badcfe;
private $d0 = 0x10325476;
//Convert a character to its binary representation using ASCII
private function convertCharToByteString($char) {
$charNum = ord($char);
$charNumString = decbin($charNum);
$charNumString = str_pad($charNumString, 8, '0', STR_PAD_LEFT);
return $charNumString;
}
//Takes in a number of zeroes and the string, and then adds that number of zeroes to the end of the string
private function padZeroRight($str, $amount) {
for ($i = 0; $i < $amount; $i++) {
$str .= '0';
}
return $str;
}
//Splits up a string into several pieces
private function getCharChunks($original, $length) {
$chunks = Array();
$currentChunk = null;
$currentStart = null;
$numberOfParts = ceil(strlen($original) / $length); //Get the number of chunks
for ($i = 0; $i < $numberOfParts; $i++) {
$currentStart = ($i * $length) - ($length - 1); //Get the starting position of the substring
$currentChunk = substr($original, $currentStart, $length);
$chunks[$i] = $currentChunk;
}
return $chunks;
}
//Easy way of converting multiple binary integers to array of decimal integers
private function convertChunkArrayToIntegers($chunkArray) {
$finalChunks = Array();
for ($i = 0; $i < count($chunkArray); $i++) {
$finalChunks[$i] = decbin($chunkArray[$i]);
}
return $finalChunks;
}
//Begin MD5-specific functions
private function F($B, $C, $D) {
return ($B & $C) | ((~$B) & $D);
}
private function G($B, $C, $D) {
return ($B & $D) | ($C & (~$D));
}
private function H($B, $C, $D) {
return ($B ^ $C ^ $D);
}
private function I($B, $C, $D) {
return ($C ^ ($B | (~$D)));
}
private function rotate($decimal, $bits) { //returns hex
return (($decimal << $bits) | ($decimal >> (32 - $bits))) & 0xffffffff;
}
public function __construct() {
$this->s = Array(
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21
);
for ($i = 0; $i < 64; $i++) { //Generate the constants that are defined in the specification
$this->k[$i] = floor(abs(sin($i + 1)) * pow(2, 32));
}
}
//Returns the MD5 hash of a message in string form
public function hash($message) {
$finalStr = '';
$subChunks = null;
$A = null;
$B = null;
$C = null;
$D = null;
$F = null;
$g = null;
$DTemp = null;
for ($i = 0; $i < strlen($message); $i++) { //Change the string representation of the message into a series of bits, which we can manipulate
$finalStr .= $this->convertCharToByteString(substr($finalStr, $i, 1));
}
$finalStr .= '1'; //Append 1, as the specification says to
$messageLen = strlen($finalStr);
$messageLenFinal = $messageLen % 512; //Find out how much we are under a multiple of 512
if ($messageLenFinal > 448) { //If the message length remainder is longer than 448, then we need to add some more zeroes to get it to 448 over
$remainingToAdd = (512 - $messageLenFinal) + 448; //'tip it over the edge' and then add 448 to make it 64 below 512
} else {
$remainingToAdd = 448 - $messageLenFinal;
}
$finalStr = $this->padZeroRight($finalStr, $remainingToAdd); //Add zeroes onto the end until criteria is met
//$messageLen = $messageLen % (pow(2, 64)); //Get the length of the message MOD 2 pow 64
$messageLen = strlen($finalStr);
$messageLenStr = decbin($messageLen); //Convert the decimal representation to binary
$messageLenStr = str_pad($messageLenStr, 64, "0", STR_PAD_LEFT); //Pad the message with zeroes to make it 64 bits long
$finalStr .= $messageLenStr;
$chunks = $this->getCharChunks($finalStr, 512); //Get message in 512-bit chunks
foreach ($chunks as $chunk) {
$subChunks = $this->convertChunkArrayToIntegers($this->getCharChunks($chunk, 32)); //Get sub chunks of 32-bit size
$A = $this->a0;
$B = $this->b0;
$C = $this->c0;
$D = $this->d0;
for ($i = 0; $i < 64; $i++) {
if ($i >= 0 && $i < 16) {
$F = $this->F($B, $C, $D);
$g = $i;
} elseif ($i > 15 && $i <32) {
$F = $this->G($B, $C, $D);
$g = ((5 * $i) + 1) % 16;
} elseif ($i > 31 && $i < 48) {
$F = $this->H($B, $C, $D);
$g = ((3 * $i) + 5) % 16;
} elseif ($i > 47 && $i < 64) {
$F = $this->I($B, $C, $D);
$g = (7 * $i) % 16;
}
$DTemp = $D;
$D = $C;
$C = $B;
$B = $B + $this->rotate(($A + $F + $this->k[$i] + $subChunks[$g]), $this->s[$i]);
$A = $DTemp;
}
$this->a0 += $A;
$this->b0 += $B;
$this->c0 += $C;
$this->d0 += $D;
}
$final = dechex($this->a0) . dechex($this->b0) . dechex($this->c0) . dechex($this->d0);
return $final;
}
}
Many thanks,
- Sam
The four additions you're performing at the end of a round:
$this->a0 += $A;
$this->b0 += $B;
$this->c0 += $C;
$this->d0 += $D;
are not wrapping. This is causing A/B/C/D to become too large -- this is probably why your output is ending up 160 bits long instead of 128.
Note that you'll also need to pad the results of dechex() in the final stage to avoid giving too short of a result if one of the four components ends up being very small.
(There may be other issues as well -- these are just the first ones I noticed.)
If it's an option at all, I'd strongly recommend that you use C for this project. PHP is not well suited to writing low-level crypto code; you will find yourself wrestling with issues like this often.

Remove invalid numbers (too big, too small) from array

I have an array of numbers and some numbers are obviously too big or too small relative to them all. I wonder if there is already some kind of function or algorithm that I can use in order to remove these records from array.
Here is an example of array
8
7
21
1330829238608
6
7
188
8
25
92433
19
6
At the moment all I can think about is just check if number is more than 1k or less than 1k and then do not allow it. But still I get problem since 188 does not belong here either.
Is there any good way that I can get majority of close numbers from this array and produce something like
8
7
6
7
8
6
This is what I have so far
<?php
echo '<pre>';
$startArray = Array(8, 7, 21, 1330829238608, 6, 7, 188, 8, 25, 92433, 19, 6);
print_r($startArray);
for ($i = 0; $i < count($startArray); $i++) {
if ($i != count($startArray) - 1) {
if ($startArray[$i] - 10 <= $startArray[$i + 1]) {
echo $startArray[$i] . '<br />';
}
}
}
Use array_filter:
function filter_callback($var){
return $var < 100 && $var > 2;
}
$array = array(1,1000,23,4453,123,412,321,433,4,6,2,3,5,634,32,432,45,3,4);
$filtered = array_filter($array, "filter_callback");
$arrayData = array(8, 7, 21,
1330829238608,
6, 7, 188, 8, 25,
92433,
19, 6,
);
$min = 7;
$max = 10;
$matches = array_filter( $arrayData,
function($data) use ($min,$max) {
return (($data >= $min) && ($data <= $max));
}
);
var_dump($matches);
I really gotta go but it's an easy one.
create a maximum = closest number to 0 in the array, multiplied by $delta.
any number in the array smaller than the maximum from pct. 1, but if multiplied by $delta is greater than that maximum, becomes maximum if($i<$max && $i*$delta>$max) $max = $i*$delta
trim out all numbers bigger than the current maximum.
Problem is you need a $delta. It's safe to go with 2 for delta, but if you want it adaptable don't ask me how to do it because that's cognitive neuroscience.
This can be optimized but this is what I figured out, works with diff of 20%, you can change it to whatever % you want, of course.
<?php
$startArray = array(8, 7, 21, 1330829238608, 6, 7, 188, 8, 25, 92433, 19, 6);
$groupArray = array();
$startArrayCount = count($startArray);
for ($i = 0; $i < $startArrayCount; $i++) {
// 20% of current value
$valueDiff = ($startArray[$i] / 100) * 20;
// Get minimal and maximal value
$maxValue = ($startArray[$i] + $valueDiff);
$minValue = ($startArray[$i] - $valueDiff);
// Print it out
// echo 'Diff: ' . $valueDiff . '<br />';
// echo 'Max: ' . $maxValue . '<br />';
// echo 'Min: ' . $minValue . '<br />';
$groupArray[$i] = array();
for ($n = 0; $n < $startArrayCount; $n++) {
if ($startArray[$n] <= $maxValue && $startArray[$n] >= $minValue) {
// echo 'TRUE: ' . $startArray[$n] . '<br />';
array_push($groupArray[$i], $startArray[$n]);
}
}
//echo '<hr />';
}
// Getting arrays that have most members in it
$max = count($groupArray[0]);
foreach ($groupArray as $group) {
if (count($group) > $max) {
$max = count($group);
}
}
// Taking all those arrays and combining them in one
$finishArray = array();
foreach ($groupArray as $group) {
if (count($group) == $max) {
foreach ($group as $key) {
array_push($finishArray, $key);
}
}
}
// Combining all values
$total = null;
foreach ($finishArray as $num) {
$total = $total + $num;
}
// Getting average
$average = $total / count($finishArray);
echo $average;

Categories