0

Suppose i have a number let's say 5. Now lets assume that there are 5 members. Now each member started to count 1 to 2. Those member who get 2nd number leaves and then again count start from the next member. so at last in this scenario the 3rd member stays at last.

So i tried to implement like this. First of assign members as array $v.

for($i=1 ; $i<=5 ; $i++)
{
    $v[] = $i;
}

$v1 = array_flip($v);

for($i=0 ; $i<=5 ; $i += 2 )
{   
    unset($v1[$i]);
}

echo "<pre>";
print_r($v1);

output

Array
(
    [1] => 0
    [3] => 2
    [5] => 4
)

Now i want to count the numbers from key 5(5th member) to again 1(1st member) and so on.

so at last key 3(3rd member) left.
I want to print the last member that left.

How can i achieve this?

I you can't understand then look at this Survival Strategy

7
  • Sounds like you need to remove elements off the beginning of the array and put them on the end? and reset the internal pointer to start again? you could use array_slice() and array_push() to do this Commented Mar 22, 2013 at 14:46
  • @Waygood Bro see above array assume at last iteration pointer is on key 5th on i want to count 5th key itself as 1 and again start from the 1st key as count no 2 . so the 1st key will be removed. so now key 3 and 5 only left . now key 3 count as one and key 5 as 2 so now key 5 is removed. Commented Mar 22, 2013 at 14:58
  • 2
    I read you question about four times, but still have trouble figuring out, exactly, what you want to achieve. Could you edit your question and try to explain more clearly what exactly you want to achieve? For instance are 5 members and the number 5 coincidental, or are they related? Also where does $num come from? Is that the number you talked about earlier? And what is the exact ultimate goal? If you could clear that up for me, that'd be great. Commented Mar 22, 2013 at 14:59
  • @Waygood But as you suggest i can get an idea that if we can push the last key-value pair of an array to the first and then reset the pointer and after that counting start from the first. So as the pointer get the last key-value pair it shits it to first and then start counting . so after that we get desired output. can we achieve this using forloop ? Commented Mar 22, 2013 at 15:02
  • so array_slice an element off the start (0). Not needed, push it onto end. array_slice element off start (1) - use it and finish. so we now have 2,3,4,5,0. Then repeat. Is this valid? p.s. look at array_fill(); as a constructor Commented Mar 22, 2013 at 15:02

5 Answers 5

1

Here's an Object-Oriented solution with an easy-to-follow reduce method and multiple examples.

class CountByTwoArrayReducer {

  public function __construct($array) {
    $this->array = $array;
    $this->size  = count($array);
  }

  public function reduce() {
    $this->initialize();

    while($this->hasMultipleItems()) {
      $this->next();
      $this->removeCurrentItem();
      $this->next();
    }

    return $this->finalItem();
  }

  protected function initialize() {
    $this->current   = 1;
    $this->removed   = array();
    $this->remaining = $this->size;
  }

  protected function hasMultipleItems() {
    return ($this->remaining > 1);
  }

  protected function next($start = null) {
    $next = ($start === null) ? $this->current : $start;

    do {
      $next++;
    } while(isset($this->removed[$next]));

    if($next > $this->size)
      $this->next(0);
    else
      $this->current = $next;
  }

  protected function removeCurrentItem() {
    $this->removed[$this->current] = 1;
    $this->remaining--;
  }

  protected function finalItem() {
    return $this->array[$this->current - 1];
  }

}

$examples = array(
  array('A', 'B', 'C', 'D', 'E'),
  range(1, 100),
  range(1, 1000),
  range(1, 10000)
);

foreach($examples as $example) {
  $start = microtime(true);

  $reducer = new CountByTwoArrayReducer($example);
  $result  = $reducer->reduce();

  $time = microtime(true) - $start;

  echo "Found {$result} in {$time} seconds.\n";
}
Sign up to request clarification or add additional context in comments.

Comments

1

This will remove every other item from the array until there is only a single item left.

$members = range(1, 5);

$i = 0;

while(count($members) > 1) {
 $i++;
 if($i == count($members)) $i = 0;
 unset($members[$i]);
 $members = array_values($members);
 if($i == count($members)) $i = 0;
}

echo $members[0];

3 Comments

Thanx for the code. Appreciate it . But if i set the range greater than 10000 then it will exceed the execution time and go in infinite loop.i want to exceed the range upto 10 lacs. And also it is better if code runs in less than 2 secs. thanx again.
It's not an infinite loop. It just takes a bit longer with such a large range. I'll post another solution that is more efficient.
This solution (stackoverflow.com/a/15623672/673079) can process 100,000 items in around 1 second.
0

Hmm, I can recommend two functions:

  1. http://php.net/manual/en/function.array-keys.php

    This would re-index you array, with indexes: 0, 1, 2

  2. http://php.net/manual/en/control-structures.foreach.php

    With this you can go through any array by:

    foreach($v1 as $key=>$value) { ...select maximum, etc. ... }

1 Comment

Consider adding relevant code and not just linking off to another page. If those links ever break, your answer won't really help future visitors.
0
<?php

function build_thieves($thieves)
{
    return range(1, $thieves);
}

function kill_thief(&$cave)
{
    if(sizeof($cave)==1)
    {
        $thief=array_slice($cave, 0, 1);
        echo $thief.' survived';
        return false;
    }

    $thief=array_slice($cave, 0, 1);
    array_push($cave, $thief);

    $thief=array_slice($cave, 0, 1);
    echo $thief.' killed';
    return true;
}

$cave=build_thieves(5);
$got_data=true;
while($got_data)
{
    $got_data=kill_thief($cave);
}

Adjusted to every 2nd, not every 3rd. And starting from 1 not 0

Comments

0

This answer is a bit more complex, but it is much more efficient. It doesn't create an array of items and then remove them. It starts with a value (e.g. 1) and calculates the next item that has not been removed yet. Then, it flags it as removed. If you actually have an array of items, the index of the final item will be $current - 1. The example below uses values 1 through 10,000. On my machine, it takes just over 0.05 seconds.

define('SIZE', 10000);

/**
 * Helper function to return the next value
 */
function get_next($current, &$removed) {
  $next = $current;
  do {
    $next++;
  } while(isset($removed[$next]));

  return ($next > SIZE) ? get_next(0, $removed) : $next;
}

$current   = 1;
$removed   = array();
$remaining = SIZE;

$start_time = microtime(true);

while($remaining > 1) {
  $current           = get_next($current, $removed);
  $removed[$current] = 1;
  $remaining         = SIZE - count($removed);
  $current           = get_next($current, $removed);
}

$total_time = microtime(true) - $start_time;

echo "Processed " . SIZE . " items\n";
echo "Winning item: {$current}\n";
echo "Total time: {$total_time} seconds\n";

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.