combine array entries with every other entry - php

Sorry for the title as it looks like most of the other questions about combining arrays, but I don't know how to write it more specific.
I need a PHP function, which combines the entries of one array (dynamic size from 1 to any) to strings in every possible combination.
Here is an example with 4 entries:
$input = array('e1','e2','e3','e4);
This should be the result:
$result = array(
0 => 'e1',
1 => 'e1-e2',
2 => 'e1-e2-e3',
3 => 'e1-e2-e3-e4',
4 => 'e1-e2-e4',
5 => 'e1-e3',
6 => 'e1-e3-e4',
7 => 'e1-e4'
8 => 'e2',
9 => 'e2-e3',
10 => 'e2-e3-e4',
11 => 'e2-e4',
12 => 'e3',
13 => 'e3-e4',
14 => 'e4'
);
The sorting of the input array is relevant as it affects the output.
And as you see, there should be an result like e1-e2 but no e2-e1.
It seems really complicated, as the input array could have any count of entries.
I don't even know if there is a mathematical construct or a name which describes such a case.
Has anybody done this before?

You are saying that there might be any number of entries in the array so I'm assuming that you aren't manually inserting the data and there would be some source or code entering the data. Can you describe that? It might be easier to directly store it as per your requirement than having an array and then changing it as per your requirement
This might be helpful Finding the subsets of an array in PHP

I have managed to bodge together a code that creates the output you want from the input you have.
I think I have understood the logic of when and why each item looks the way it deos. But Im not sure, so test it carefully before using it live.
I have a hard time explaining the code since it's really a bodge.
But I use array_slice to grab the values needed in the strings, and implode to add the - between the values.
$in = array('e1','e2','e3','e4');
//$new =[];
$count = count($in);
Foreach($in as $key => $val){
$new[] = $val; // add first value
// loop through in to greate the long incrementing string
For($i=$key; $i<=$count-$key;$i++){
if($key != 0){
$new[] = implode("-",array_slice($in,$key,$i));
}else{
if($i - $key>1) $new[] = implode("-",array_slice($in,$key,$i));
}
}
// all but second to last except if iteration has come to far
if($count-2-$key >1) $new[] = Implode("-",Array_slice($in,$key,$count-2)). "-". $in[$count-1];
// $key (skip one) next one. except if iteration has come to far
If($count-2-$key >1) $new[] = $in[$key] . "-" . $in[$key+2];
// $key (skip one) rest of array except if iteration has come to far
if($count-2-$key > 1) $new[] = $in[$key] ."-". Implode("-",Array_slice($in,$key+2));
// $key and last item, except if iteration has come to far
if($count-1 - $key >1) $new[] = $in[$key] ."-". $in[$count-1];
}
$new = array_unique($new); // remove any duplicates that may have been created
https://3v4l.org/uEfh6

here is a modificated version of Finding the subsets of an array in PHP
function powerSet($in,$minLength = 1) {
$count = count($in);
$keys = array_keys($in);
$members = pow(2,$count);
$combinations = array();
for ($i = 0; $i < $members; $i++) {
$b = sprintf("%0".$count."b",$i);
$out = array();
for ($j = 0; $j < $count; $j++) {
if ($b{$j} == '1') {
$out[] = $keys[$j];
}
}
if (count($out) >= $minLength) {
$combinations[] = $out;
}
}
$result = array();
foreach ($combinations as $combination) {
$values = array();
foreach ($combination as $key) {
$values[$key] = $in[$key];
}
$result[] = implode('-', $values);
}
sort($result);
return $result;
}
This seems to work.

Related

How to add up the total of 1 array + the total of another array

I am a rookie beginner with PHP, i was wondering how i could add up the total number from 1 array + the total number of another array together. I managed to make this code with help from stackoverflow answers on google. I don't know why but it's no where explained or i am looking over it. Been looking for almost an hour to make this work. Here is the code:
<?php
$array = array(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19);
$odds = array();
$even = array();
foreach($array as $val) {
if($val % 2 == 0) {
$even[] = $val;
} else {
$odds[] = $val;
}
}
$array = array();
foreach($even as $key => $val) {
$array[] = $val;
if(isset($odds[$key])) {
$array[] = $odds[$key];
}
}
echo '<b>Oneven</b> ';
print_r($odds);
echo '<br><br><br>';
echo "Bovenstaande <b>oneven</b> getallen bijelkaar opgeteld = " . array_sum($odds) . "\n";
echo '<br><br><br><hr style="margin-top:2%;margin-bottom:4%;">';
/* Array nummer 2 */
$array = array(20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40);
$odds = array();
$even = array();
foreach($array as $val) {
if($val % 2 == 0) {
$even[] = $val;
} else {
$odds[] = $val;
}
}
$array = array();
foreach($even as $key => $val) {
$array[] = $val;
if(isset($odds[$key])) {
$array[] = $odds[$key];
}
}
echo '<b>Even</b> ';
print_r($even);
echo '<br><br><br>';
echo "Bovenstaande <b>even</b> getallen bijelkaar opgeteld = " . array_sum($even) . "\n";
?>
So i don't know how to do it in another way but i have array 1 code at first and then code 2 begins with another array.
The thing is that i want to make a program that includes the odd numbers from 1 to 19 and the even numbers from 20 to 40 and then count the total of those 2 array's. Is there a way to do this in 1 code and count up the total of those 2 array's together. I already have that part of code that it counts the array, in code 1 that is 100 and in code 2 it is 330.
330+100=430 that's the output that i want. Why is that so hard? haha...
I appreciate the help and time effort.
First off, there's a lot of complexity involved in creating the initial array and then extracting only the odd numbers. This complexity can be eliminating by using the range and array_filter functions like so:
$odds = array_filter(range(1, 19), function($elem) {
return $elem & 1;
});
$even = array_filter(range(20, 40), function($elem) {
return $elem % 2 == 0;
});
to calculate sum of the sum of odds plus the sum of even, you can simply merge them together and use array_sum in the same you are doing for the individual arrays
$totalSum = array_sum(array_merge($odds, $even))
As #Darragh pointed out in the comments, you can simplify the array creation by specifying a step parameter for the range function.
$odds = range(1, 19, 2) // start at 1, go up to 19, by increments of 2

Sort Array by combining orders from multiple Arrays

I'm making a simple search engine, and I have already indexed a lot of websites in a MySQL database. Now I would like to get a relevant list of results by keywords.
Websites are indexed in my database with the following columns : hostname (without protocol an port), title, description. (We don't care about path)
When I type some keywords on my search engine homepage, it first starts by fetching 50 websites using FULLTEXT indexes.
Now, and because using Levenshtein algorithm in MySQL is really slow, I would like to sort those results with the Levenshtein PHP function for each columns I listed previously.
I would like to sort them in this order (most important first) : hostname, title, and then description.
So I have five arrays :
$results, returned by MySQL
$sorted_by_mysql, containing keys of $results in the original order : 0, 1, 2, ...
$sorted_by_hostname, containing keys of $results sorted by hostname's relevance using Levenshtein, ex: 3, 0, 1, 2, ...
$sorted_by_title, containing keys of $results sorted by title's relevance using Levenshtein, ex: 0, 2, 1, 3, ...
$sorted_by_description, containing keys of $results sorted by description's relevance using Levenshtein, ex: 1, 3, 0, 2, ...
Here's the code :
$results = $req->fetchAll();
$search = strtolower($q);
$temp_arr = [];
$sorted_by_mysql = $sorted_by_hostname = $sorted_by_title = $sorted_by_description = [];
// We keep the original order in an array
for($i = 0; $i < count($results); $i++) $sorted_by_mysql[] = $i;
// Sort by hostname
for($i = 0; $i < count($results); $i++) $temp_arr[$i] = levenshtein($search, strtolower($results[$i]->hostname));
asort($temp_arr);
foreach($temp_arr as $k => $v) $sorted_by_hostname[] = $k;
// Sort by title
for($i = 0; $i < count($results); $i++) $temp_arr[$i] = levenshtein($search, strtolower($results[$i]->title));
asort($temp_arr);
foreach($temp_arr as $k => $v) $sorted_by_title[] = $k;
// Sort by description
for($i = 0; $i < count($results); $i++) $temp_arr[$i] = levenshtein($search, strtolower($results[$i]->description));
asort($temp_arr);
foreach($temp_arr as $k => $v) $sorted_by_description[] = $k;
Finally I would like to sort $results by combining (by priority) all thoses different arrays. But I have no idea on how, so here's where I need some help !
EDIT : Solution !
$data = $req->fetchAll();
$search = strtolower($q);
$temp = [];
foreach($data as $i => $row) {
$temp[] = [
'id' => $i,
'lev1' => levenshtein($search, strtolower($row->hostname)),
'lev2' => levenshtein($search, strtolower($row->title)),
'lev3' => levenshtein($search, strtolower($row->description))
];
}
$sorted = array_orderby($temp, 'lev1', SORT_ASC, 'lev2', SORT_ASC, 'lev3', SORT_ASC, 'id', SORT_ASC);
$results = [];
foreach($sorted as $row) {
$results[] = $data[$row['id']];
}
// Perfectly sorted !
Here's array_orderby function :
// Credits : jimpoz at jimpoz dot com (PHP.net)
function array_orderby()
{
$args = func_get_args();
$data = array_shift($args);
foreach ($args as $n => $field) {
if (is_string($field)) {
$tmp = array();
foreach ($data as $key => $row)
$tmp[$key] = $row[$field];
$args[$n] = $tmp;
}
}
$args[] = &$data;
call_user_func_array('array_multisort', $args);
return array_pop($args);
}
See the answer to this SO question, they have a similar need but have structured their data in a way that makes the answer easier. It looks like PHP supports sorting by multiple attributes (in descending priority) as long as those attributes are built into the associative array that's being sorted.
To apply this approach to your data, you'll probably want to restructure your results into one giant associative array where each element of the array contains a value for each "field" you're aiming to sort by. Does that make sense?
Good luck!

PHP Array shuffle, keeping unique

this is my first php script and problem, I've searched hours with no conclusion other than looping a function" too many laterations". but it doesn't solve my problem I've never studied programming or what ever so I'm hoping that there is an educated person to fill me in on this:
I have an array that contains 120 elements; consists of duplicates eg:
myArray = [0]= item_1, [1] = item _1, [2] = item_2, [3] = item_3 ect..
Briefly I'm trying to make a flash php pokermachine but I need these items in the array to be shuffled BUT I do not want the duplicates to be next to each other after the shuffle but I need the duplicates to be still in the array
I can't do a loop function to check this because it will change the shuffle too many times which will effect the odds of the game: below is what I currently have:
/ * Removed the link here that is no longer available */
you may notice at times it will double up with 2 items in the same reel
Basically I created the virtual reel dynamically with php.ini file
these values are repeatedly pushed into an array($virtualreel) so the value may appear 10 times in the reel and another value will appear 5 times variating the odds. Then after I take a random slice() from the $virtualreel to display 3 vars from this reel and repeat the loop 4 more times for the other reels, also I only can shuffle once as I want the slice() to be from the same reels array order
I only shuffle every new spin not running loop functions to shuffle if I double up on a slice(array,3 items).
hope I've explained what I'm after well enough to give you guys an idea.
You can use this function:
<?php
function shuffleArray($myArray) {
$value_count = array_count_values($myArray);
foreach($value_count as $key=>$value) {
if ($value > count($myArray)/2) {
return false;
}
}
$last_value = $myArray[count($myArray) - 1];
unset($myArray[count($myArray) - 1]);
$shuffle = array();
$last = false;
while (count($myArray) > 0) {
$keys = array_keys($myArray);
$i = round(rand(0, count($keys) - 1));
while ($last === $myArray[$keys[$i]]) {
$i = round(rand(0, count($keys) - 1));
}
$shuffle[] = $myArray[$keys[$i]];
$last = $myArray[$keys[$i]];
unset($myArray[$keys[$i]]);
}
if ($last_value === $last) {
$i = 0;
foreach($shuffle as $key=>$value) {
if ($value !== $last_value) {
$i = $key;
break;
}
}
array_splice($shuffle, $i + 1, 0, $last_value);
} else {
$shuffle[] = $last_value;
}
return $shuffle;
}
print_r(shuffleArray(array(1,5,5,3,7,7)));
Why not just:
Edit :
$shuffled = array();
while(count($to_shuffle) > 0):
$i = rand(0, count($to_shuffle)-1);
$shuffled[] = $to_shuffle[$i];
array_splice($to_shuffle, $i, 1,null);
endwhile;
I think this is what you were expecting, if you don't mind not preserving the association between keys and values.

how to skip elements in foreach loop

I want to skip some records in a foreach loop.
For example, there are 68 records in the loop. How can I skip 20 records and start from record #21?
Five solutions come to mind:
Double addressing via array_keys
The problem with for loops is that the keys may be strings or not continues numbers therefore you must use "double addressing" (or "table lookup", call it whatever you want) and access the array via an array of it's keys.
// Initialize 25 items
$array = range( 1, 25, 1);
// You need to get array keys because it may be associative array
// Or it it will contain keys 0,1,2,5,6...
// If you have indexes staring from zero and continuous (eg. from db->fetch_all)
// you can just omit this
$keys = array_keys($array);
for( $i = 21; $i < 25; $i++){
echo $array[ $keys[ $i]] . "\n";
// echo $array[$i] . "\n"; // with continuous numeric keys
}
Skipping records with foreach
I don't believe that this is a good way to do this (except the case that you have LARGE arrays and slicing it or generating array of keys would use large amount of memory, which 68 is definitively not), but maybe it'll work: :)
$i = 0;
foreach( $array as $key => $item){
if( $i++ < 21){
continue;
}
echo $item . "\n";
}
Using array slice to get sub part or array
Just get piece of array and use it in normal foreach loop.
$sub = array_slice( $array, 21, null, true);
foreach( $sub as $key => $item){
echo $item . "\n";
}
Using next()
If you could set up internal array pointer to 21 (let's say in previous foreach loop with break inside, $array[21] doesn't work, I've checked :P) you could do this (won't work if data in array === false):
while( ($row = next( $array)) !== false){
echo $row;
}
btw: I like hakre's answer most.
Using ArrayIterator
Probably studying documentation is the best comment for this one.
// Initialize array iterator
$obj = new ArrayIterator( $array);
$obj->seek(21); // Set to right position
while( $obj->valid()){ // Whether we do have valid offset right now
echo $obj->current() . "\n";
$obj->next(); // Switch to next object
}
$i = 0;
foreach ($query)
{
if ($i++ < 20) continue;
/* php code to execute if record 21+ */
}
if want to skipped some index then make an array with skipped index and check by in_array function inside the foreach loop if match then it will be skip.
Example:
//you have an array like that
$data = array(
'1' => 'Hello world',
'2' => 'Hello world2',
'3' => 'Hello world3',
'4' => 'Hello world4',
'5' => 'Hello world5',// you want to skip this
'6' => 'Hello world6',// you want to skip this
'7' => 'Hello world7',
'8' => 'Hello world8',
'9' => 'Hello world8',
'10' => 'Hello world8',//you want to skip this
);
//Ok Now wi make an array which contain the index wich have to skipped
$skipped = array('5', '6', '10');
foreach($data as $key => $value){
if(in_array($key, $skipped)){
continue;
}
//do your stuf
}
You have not told what "records" actually is, so as I don't know, I assume there is a RecordIterator available (if not, it is likely that there is some other fitting iterator available):
$recordsIterator = new RecordIterator($records);
$limited = new LimitIterator($recordsIterator, 20);
foreach($limited as $record)
{
...
}
The answer here is to use foreach with a LimitIterator.
See as well: How to start a foreach loop at a specific index in PHP
I'm not sure why you would be using a foreach for this goal, and without your code it's hard to say whether this is the best approach. But, assuming there is a good reason to use it, here's the smallest version I can think of off the top of my head:
$count = 0;
foreach( $someArray as $index => $value ){
if( $count++ < 20 ){
continue;
}
// rest of foreach loop goes here
}
The continue causes the foreach to skip back to the beginning and move on to the next element in the array. It's extremely useful for disregarding parts of an array which you don't want to be processed in a foreach loop.
for($i = 20; $i <= 68; $i++){
//do stuff
}
This is better than a foreach loop because it only loops over the elements you want.
Ask if you have any questions
array.forEach(function(element,index){
if(index >= 21){
//Do Something
}
});
Element would be the current value of index.
Index increases with each turn through the loop.
IE 0,1,2,3,4,5;
array[index];

php looping through 2D array

I access the following values like this.
$result->{'HistoricalPricesResult'}->HistoricalPricesResult[0]->Price
$result->{'HistoricalPricesResult'}->HistoricalPricesResult[0]->Low
//next row
$result->{'HistoricalPricesResult'}->HistoricalPricesResult[1]->Price
$result->{'HistoricalPricesResult'}->HistoricalPricesResult[1]->Low
However I need to consolidate this to
$values[0][price]
$values[0][low]
$values[1][price]
$values[1][low]
2 other strange things. The values are strings and I need them to be decimals(2 decimal points) and also the min and the max for price and low accross all the rows
Well the obvious way to build an array of values would be:
$values = array();
for($i = 0; $i < some_maximum_value; $i++) {
$values[$i] = array(
'price' => $result->{'HistoricalPricesResult'}->HistoricalPricesResult[$i]->Price,
'low' => $result->{'HistoricalPricesResult'}->HistoricalPricesResult[$i]->Low,
);
}
TADAAAAAA!!!!
$values = array();
foreach($result->{'HistoricalPricesResult'}->HistoricalPricesResult as $key => $obj){
$values[$key]['price'] = $obj->Price;
$values[$key]['low'] = $obj->low;
}
$myVals = array();
foreach ($result->{'HistoricalPricesResult'}->HistoricalPricesResult as $key => $v)
{
$myVals[$key]['price'] = 1.0 * $c->Price; //hoping string has 2 after the decimal
$myVals[$key]['low'] = 1.0 * $c->Low
}
Try to figure out max/min yourself
Check out foreach loops and string/float conversion
http://us2.php.net/manual/en/control-structures.foreach.php
http://www.php.net/manual/en/language.types.string.php#language.types.string.conversion

Categories