
Array Iteration Interview Problem - jazzychad
http://blog.jazzychad.net/2012/08/01/array-iteration-problem.html
======
tylermenezes
> _Lots of people do this, which is fascinating to me, to handle the negative
> n case_

It makes sense, because performance differences between that and the "optimal"
solutions are usually negligible, and the "optimal" solutions aren't usually
optimal when you take into account readability and maintainability.

Embedded development is significantly different than developing for the web.
Buying more servers is usually more efficient than taking twice as long to
develop and update code. Interviewing with people who refuse to acknowledge
this is extremely frustrating.

~~~
revelation
Performance differences are anything but negligible. In the case of the
"billion elements", you are now spending the majority of time for reversing
the array twice.

As a programmer you should always know what kind of cost you are incurring,
both asymptotically and down to cycles.

Trying to condense all the cases into one (using reverse or local state like
'step' from OPs version) is what hurts readability and maintainability.

Also, the "buy more metal" argument is hardly applicable for implementing this
one way or another. Its an argument for using whatever platform you are most
productive in.

~~~
sanderjd
> As a programmer you should always know what kind of cost you are incurring,
> both asymptotically and down to cycles.

No, as a programmer, you should _be able to determine_ what kind of cost you
are incurring _when it matters_ , and much more importantly, you should be
able to determine when it matters and when it doesn't.

------
netmeta4
My python solution, with commentary.

First step: the increment requirement, the in place requirement, the short
circuit requirement, are all the same thing. So, break that part off.

    
    
        def addl(list, target, n):
    
            indexes = lazy_find_n(list, target, n)
            for index in indexes:
                list[index] += 1
    

The general purpose for loop gives me the willies.

    
    
        for (var i = start; i != stop; i += step) {
          if (arr[i] == val) {
            arr[i]++;
            count++;
            ...
    

What is the difference between i += step, arr[i]++, count++? Are you
absolutely sure your start, stop, step & count won't over run your array
boundaries? Are you willing to bet control of your users, CPU instruction
pointer? What if a new requirement is an operation besides increment? What
happens when the next guy, implementing the new operation, isn't as careful
with his loop/subscript conditions? (end rant)

Second step: create a lazy_find_n() which returns an iterator of the indexes
of the list items we want to modify.

    
    
        from itertools import ifilter, islice
    
        def lazy_find_n(list, target, n):
            # generate indexes in desired direction
            if n >= 0:
                indexes = xrange(len(list))
            else:
                indexes = xrange(len(list)-1, -1, -1)
    
            # filter indexes for items matching target
            indexes = ifilter(lambda i : list[i] == target, indexes)
    
            # only as many as requested
            if n != 0: indexes = islice(indexes, abs(n))
    
            return indexes
    

Since xrange, ifilter and islice return iterators, the value of indexes is
computed only as needed. That is, if islice only returns a 2 item iterator, it
doesn't matter how many items the iterator from ifilter would have returned,
as long as there are at least 2. (If there are less, islice returns less.)
Furthermore, the iterator from xrange only processes until ifilter, and islice
are satisfied.

------
AustinYun
Here's my second Javascript draft. I intend to refactor it tomorrow so that
the three if branches are unrolled into their own functions. Especially since
some bizarre facet of Javascript's type coercion makes it impossible to do
early returns inside the iterator function ([] << 1 somehow comes out as 1,
not [1]).

[https://github.com/austinyun/challenges/blob/master/array-
it...](https://github.com/austinyun/challenges/blob/master/array-iteration-
interview-problem/add1.js)

    
    
        function increment_where_pure(array, match, n) {
            var count;
        
            function iterator(f, acc, item) {
                // f is the function used to combine array arguments -- push || unshift
                if (count === 0) {
                    f.call(acc, item);
                } else {
                    if (item === match) { item += 1; }
                    f.call(acc, item);
                    count -= 1;
                }
                return acc;
            }
        
            if (n === 0) {
                return _.map(array, function(item) {
                    return item === match ? item + 1 : item;
                });
            }
        
            if (n > 0) {
                count = n + 1;
                return _.reduce(array, iterator.bind(null, Array.prototype.push), []);
            }
        
            if (n < 0) {
                count = -n + 1;
                return _.reduceRight(array, iterator.bind(null, Array.prototype.unshift), []);
            }
        }

------
telemachos
I've posted and deleted this a few times, since I keep rethinking it. This is
a Lua version, and I'm pretty new to Lua (it's good practice). No reverses
needed; just numeric for loops.

I'd rather keep n = 0 as a separate case since it doesn't need to consider a
break point or a count variable. The test - Is n 0? - happens once and by
including it, you can omit a lot of pointless tests - Am I at the breakpoint?
- and increments - Add another one to count. Those tests and increments seem
much worse than the single test - especially if the array (a table in Lua)
will grow to very, very large sizes.

But I would be happy to hear if I'm looking at it wrong or missing a good
trick in Lua.

    
    
        function add1(t, val, n)
            if n >= 0 then
                start = 1; stop = #t; step = 1
            else
                start = #t; stop = 1; step = -1
            end
        
            if n == 0 then
                for i = start, stop, step do
                    if t[i] == val then t[i] = t[i] + 1 end
                end
            else
                break_point = math.abs(n)
                count = 0
                for i = start, stop, step do
                    if count == break_point then break end
        
                    if t[i] == val then
                        t[i] = t[i] + 1
                        count = count + 1
                    end
                end
            end
        
            return t
        end

------
thomaspun
I changed the interface to what I think it's more 'Ruby'. If you are looking
for in-place solution, we should use the ! to indicate it's more 'dangerous'
than the other solution which returns a new copy.

I'm new to Ruby so I'd love to hear feedback from other more experienced
Rubyists on HN. (And I couldn't find reverse_each_with_index so I had to write
my own.)

<https://github.com/tpun/add1/blob/master/add1.rb>

------
brendino
While the implementation of this would be pretty straightforward, the method
signature you're asking for seems convoluted, in my opinion. Here's why:

\- "add1" is not very descriptive of what the method actually does, since it
adds one, but only sometimes. This title makes it sound like the method simply
increments each value by one.

\- When you say "if it is zero, do this, but if it is positive, do this...",
this thinking creates a "secret handshake" in your code, so a new developer
would have to read the method in depth to understand what it does in each
case.

\- If this method will have widespread use in your code for arrays, consider
extending the array class with the method, so that you can call it directly on
an instance of an array.

I propose you change the method signature to:

    
    
      increment_where_value_equals(value, options = {})
    

So you could call it like:

    
    
      increment_where_value_equals 1, { :direction => :forward, :limit => 2 }
    

or even like:

    
    
      increment_where_value_equals 1
    

While the implementation may get a little more complicated this way, you're
making the method signature much more clear and descriptive, which will lead
to better code overall.

------
telemachos
> Are you using iterators like .each or .map, or are you using a normal,
> index-based for loop?

I doubt you mean anything very judgmental by 'normal', but this still jumped
out at me. In Ruby an index-based for loop is pretty unusual. The for loop is
non-idiomatic, and it also has a scope leak:
<https://gist.github.com/3232118>.

~~~
jazzychad
hmm, my apologies if that sounded judgmental. I started coding a long time
ago, so doing for loops was a very fundamental part of learning how to code. I
(incorrectly?) assumed most people learned that form of looping first.

~~~
telemachos
Again, I didn't really think you were being judgmental. It's just that in
Ruby, the for loop definitely doesn't have pride of place at all. You're may
be right that most programmers learn languages where for is more common, but I
wonder about people who start with Ruby. That is, do they think for is weirdly
primitive when they start doing Javascript?

Anyhow, no offense taken at all. But I would be shocked if any Rubyist _did_
use for.

~~~
bunderbunder
Even in languages like C# the standard for-loop seems to be heading in the
direction of being considered harmful. Its status hasn't gone nearly as far
along the path as for Ruby, but the tide's turning that way.

As far as creating a new array (or several new arrays) goes, there are some
new considerations such as composability that are starting to be valued more
highly than efficiency. And pure functions are more composable than ones that
mutate the existing data.

Granted, the n < 0 case could still be handled in a way that's more efficient
but still pure by allocating an array and filling it backward rather than
using two reverses and an iterator.

------
rcfox
Please never actually write code like this!

Here's my C version. :)

    
    
        #include <stdio.h>
        #include <stdlib.h>
        
        #define NELEMS(x) (sizeof(x) / sizeof(x[0]))
        
        void add1(int* arr, size_t size, int val, int n) {
            if(!arr || size == 0) return;
        
        #define add1_start ( n >= 0 ? 0 : size-1 )
        #define add1_end (( n >= 0 ? i < size : i >= 0 ) && ( n != 0 ? inc < abs(n) : 1 ))
        #define add1_iterate ( n >= 0 ? ++i : --i )
        
            int inc = 0;
            for(int i = add1_start; add1_end; add1_iterate) {
                arr[i] += (arr[i] == val ? ++inc, 1 : 0);
            }
        }
        
        void test(int val, int n) {
            int arr[] = {1,4,1,5,1};
            add1(arr,NELEMS(arr),val,n);
        
            for(int i = 0; i < NELEMS(arr); ++i) {
                printf("%d ",arr[i]);
            }
            printf("\n");
        }
        
        int main() {
            test(1,0);
            test(1,2);
            test(1,-2);
            return 0;
        }

------
spicyj
My Python solution:

    
    
        def add1(arr, val, n):
            it = xrange(len(arr))
            if n < 0:
                it = reversed(it)
                n *= -1
    
            found = 0
            for i in it:
                if arr[i] == val:
                    arr[i] += 1
                    found += 1
                    if found == n:
                        break
    
            return arr

~~~
mef
One for ruby 1.9:

    
    
      def add1(arr, val, n)
        limit = (n == 0 ? arr.length : n.abs)
    
        enumerator = (n < 0 ? (arr.length-1).downto(0) : (0).upto(arr.length-1))
        enumerator.each do |i|
          if arr[i] == val
            arr[i] += 1
            limit -= 1
          end
    
          break if limit == 0
        end
        arr
      end

------
jmkeyes
Chicken Scheme:

    
    
      (use vector-lib)
    
      (define (add1 vec val n)
        (define *clone* (vector-copy vec)))
        (define fold-using (if (>= n 0) vector-fold vector-fold-right))
        (define (substitution-of total-replacements value)
          (define replacements-left (if (= total-replacements 0) (vector-length vec) (abs total-replacements)))
          (lambda (index mutable-vector current-element)
            (if (and (= current-element value) (> replacements-left 0)
              (begin
                (vector-set! mutable-vector index (+ 1 current-element))
                (set! replacements-left (- replacements-left 1))))
            mutable-vector))
      (fold-using (substitution-of n val) *clone* vec))
    

I don't like that I have to make a copy of the vector though. Maybe unfold ...

------
knowtheory
> _My background is mainly in embedded systems programming. My main concern
> when I code is for speed and efficiencey, both in runtime and in memory
> consumption._

Do you specify this to your candidates when they write their code?

This is the thing that annoys me most about interview programming questions.
If you don't give me constraints, I am going to implement a naïve version of
your requirements, because you have not given me any additional criteria by
which you are going to judge my code.

Knowing things about what sorts of inputs the method has to expect (should I
assume that i'm going to encounter a billion elements or not?) is really
important to judge correctness of fit, or whether you're just wasting your
time thinking about cases you'll never encounter.

~~~
mbrameld
Part of being a good developer is teasing the constraints out of the customer.
You're never going to be handed a perfect requirement. If you're not given
constraints don't get annoyed, simply ask about them.

~~~
jazzychad
Precisely. I also say, "This is a very open-ended question in which I am
intentionally vague on some points. Ask me about information you want or
points you need clarified."

Like I said, I have no desire for them to create the "perfect, correct"
solution; but I do want to know how they think about a problem and what
questions they ask in the face of deficient information. I proactively
encourage them to do so, so I am not trying to trick them into failure or
anything.

~~~
sanderjd
A problem with entirely made-up domain-less questions like this is that any
additional constraints are equally as arbitrary as the question itself, and
thus difficult to probe for in the same way that someone would probe a
customer for constraints to real problems.

It seems like you're very interested in people asking questions like "how big
might the array be" or "what order of time can you afford to wait for the
answer to this", to which you might answer "a billion" or, "as little as
possible", but those questions are very different and less meaningful than
questions like "how many users will this system have", and "how much time can
users of this system afford to wait for a response", even though the answers
may be the same.

------
prophetjohn
Here's my 10-minutes-of-thought JavaScript implementation. I was going to do
Ruby until I realized how long it's been since I wrote any Ruby.

I only got it down to 2 cases

    
    
        function add1(arr, val, n) {
          var m = 0, i;
        
          if(n > 0) {
            for(i = 0; i < arr.length && m < n; i++) {
              if(arr[i] === val) {
                arr[i]++;
                m++;
              }
            }
          } else {
            for(i = arr.length; i >= 0 && (m !== n || !n); i--) {
              if(arr[i] === val) {
                arr[i]++;
                m--;
              }
            }
          }
          console.log(arr);
        }

------
pbsd
Overly complex C++11: <http://ideone.com/yHzej>

The output assembly is actually pretty good (std::vector specialization):

    
    
            ; prologue
        L19:
    	add	eax, esi
    	cmp	ebx, eax
    	je	L4
        L8:
    	mov	ecx, DWORD PTR [eax]
    	cmp	ecx, DWORD PTR [edi]
    	.p2align 4,,3
    	jne	L10
    	add	ecx, 1
    	sub	edx, 1
    	mov	DWORD PTR [eax], ecx
        L10:
    	test	edx, edx
    	jg	L19
        L4:
            ; epilogue

------
tikhon
this reminds me of how even fulton, the author of the ruby way, made a
critical mistake in "the ruby way" 1st edition (fixed in 2nd edition) and matz
chimed in saying " "Don't modify the receiver while you are iterating over
it." [http://www.justskins.com/forums/collect-with-block-
modifying...](http://www.justskins.com/forums/collect-with-block-
modifying-71472.html)

------
jkbr
My Python version (in-place, no reverse):

    
    
        def add1(arr, val, n):
            todo = abs(n) or len(arr)
            seq = xrange(0, len(arr), 1) if n >= 0 else xrange(len(arr) - 1, 0, -1)
            for i in seq:
                if arr[i] == val:
                    arr[i] += 1
                    todo -= 1
                    if not todo:
                        break
            return arr

------
kbenson
perl, for fun:

    
    
      sub add1 {
          my ($arrayref,$val,$count) = @_;
          # Just incremet matches and return if we aren't limited
          # Useless return of array ref
          return \map { $_++ if $_ == $val } @$arrayref unless $count;
          # increment up to count matches
          for ($count<0 ? reverse @$arrayref : @$arrayref) {
              next if $_ != $val;
              $_++;
              # Advance count towards zero
              $count<0 ? $count++ : $count--;
              return if $count == 0;
          }
      }
    

Splitting the loop into separate versions for positive and negative counts is
quicker than checking if count is positive or negative each iteration, but I
figured that's a step more than I wanted to take it.

Alternatively, defining a variable for the amount the $count changes (-1 or 1)
and just adding that to count would work as well, but I'm working under the
assumption that's less likely to be special cased in the interpreter than
post-{in,de}crement.

Edit: Clarified reasoning behind post-increment, etc.

------
azylman
Solution in CoffeeScript:

    
    
        add1 = (arr, val, n) ->
          n = arr.length if n is 0
          arr = arr.reverse() if n < 0
          count = 0
          for num, i in arr
            break if count > (Math.abs n)
            arr[i]++ if num is val
            count++
          return if n < 0 then arr.reverse() else arr

~~~
jazzychad
another double reverse... I guess coffeescript really does want to be ruby :)

~~~
cezary
Here's my version without using reverse or underscore. If coffeescript
supported reverse loops or negative indices, this would be a lot cleaner.

    
    
        add1 = (arr, val, n)->
          d = Math.abs(n||1)/(n||1)
          n = if n is 0 then arr.length else Math.abs n
          i = if d < 0 then arr.length - 1 else 0
          end = if d < 0 then 0 else arr.length
    
          while n and i isnt end
            num = arr[i]
            if num is val
              n--
              arr[i]++
            i = i + d
          arr

------
nwmcsween
I wouldn't do any of this, Ruby / Python are OO so they provide already baked
in primitives to do this, e.g:

    
    
        array.map { |e| e + val }
    

It bugs me when developers roll their own instead of utilizing what's already
been done (minus performance reasons).

------
pjm4ycombinator
With MATLAB, find is built-in!

    
    
      function arr=add1(arr,val,n)
      if n==0
          ind=find(arr==val);
      elseif n>0
          ind=find(arr==val,n);
      else
          ind=find(arr==val,-n,'last');
      end
      arr(ind)=arr(ind)+1;

------
FrankBooth

      #   n < 0  means increment up to n occurrences of val
      #          from right-to-left (backward)
    

Presumably you mean "increment up to abs(n) occurrences", otherwise this
requirement is nonsensical.

~~~
jazzychad
yes, that is technically correct (the best kind), however everyone has
understood it as intended so far. I also state it like that so as not to give
a tip that abs() might be helpful to them down the line.

~~~
spicyj
You could also say -n if you didn't want to say abs. I found the problem
confusing because of how it was written.

Also, unless I'm mistaken, you can lose the "if (n === 0)" case completely.

------
aidenn0
In Common Lisp:

    
    
        (defun increment (sequence val n)
          (substitute (1+ val) val sequence
                  :from-end (< n 0)
                  :count (if (= n 0) nil (abs n)))

~~~
spicyj
I don't know Common Lisp, but it doesn't look to me like that works. Can you
explain how it works?

~~~
nandemo
I don't know Common Lisp either but if you know any Lisp it's quite readable.
I'll guess an explanation (without looking at any docs) and let the real
lispers correct me.

 _substitute_ traverses the list _sequence_ replace any element equal to _val_
with _val + 1_. I don't know if sequence does this in-place but that doesn't
necessarily affect the correctness, since this wasn't mentioned in the spec.

If used as above then all elements equal to val would be replaced. But there
are 2 additional (optional?), named parameters.

 _from-end_ indicates whether to traverse the list in reverse order. It will
be true if and only if n is less than 0.

 _count_ indicates how many replacements should be made. If n is 0, then this
will be _nil_ , which indicates "replace all". Otherwise it will be the
absolute value of n.

It's likely that the interviewer would ask you to implement _substitute_ ,
though.

------
munin
it's interesting that you say you have a functional background but then
chastise people for not modifying the array in place ...?

~~~
ww520
And using map that short-circuits.

------
rurounijones
I would like to see some of the ruby solutions you ran across in your
interviews to see how rubyish they may have been be.

------
mdj
The OP's implementation wastes cycles in the n == 0 case because the statement
`if (count == n)` is unnecessary.

~~~
ben0x539
And surely the `count++;` statement.

I don't see an obvious solution that doesn't "unroll" the three cases and
doesn't waste any cycles, but maybe that is why I don't work at OP's company.
;)

~~~
jazzychad
yes, the count++ (and count variable itself) are unnecessary since I could
just text n against 0 and then break. good catch.

~~~
ben0x539
But decrementing n would still cost you cycles in the case where n was given
as 0 that you wouldn't need if you had separated out that case, wouldn't it?

~~~
jazzychad
yes, that's right. Then it becomes a tradeoff of cycles and code-readability
since I would have to special case for 0.

------
okertanov
here is my "c++ with stl" version. it's in-place, with only one separate case
and w/o array reversing at all.

[http://okertanov.github.com/2012/08/03/Array-Iteration-
Inter...](http://okertanov.github.com/2012/08/03/Array-Iteration-Interview-
Problem/)

------
robomartin
OK, here's a C version. Had to add a parameter, of course:

    
    
      void add1(int arr[], int length, int val, int n)
      {
        int direction  = n >= 0;
        int counter    = n == 0 ? length : abs(n);
        int index;
        
        for(int i = 0; (i < length) && (counter != 0) ; i++)
        {
          index = direction ? i : length - i;
          if(arr[index] == val)
          {
            arr[index]++;
            counter--;
          }
        }
      }
    

Verified with test vectors.

------
geuis
My javascript version, <http://jsfiddle.net/kjqTg/>

var add1 = function(arr, val, n){

    
    
        var x = n,
            end = 0;
        
        if( n < 0 ){
            arr.reverse();
            x = Math.abs(n);
        }
    
        for(var i=0, len=arr.length; i<len; i++){
                
            if( arr[i] === val )
                arr[i]++;
                
            if( x > 0 ){
                end++;
                if( end >= x+1)
                    break;
            }
                
        }
    
        if( n < 0 ) arr.reverse();
    
        return arr;    

}

console.log( add1( [1,4,1,5,1], 1, 0 ) ); // [2,4,2,5,2] console.log( add1(
[1,4,1,5,1], 1, 2 ) ); //[2,4,2,5,1] console.log( add1( [1,4,1,5,1], 1, -2 )
); //[1,4,2,5,2]​

~~~
jazzychad
another double reverse :)

------
ten_fingers
Right at first I would have two remarks. The first remark has to do with how
to describe such a problem. The second remark points to what appears to be a
serious error in the problem description.

My first remark would be that the problem statement is not in any natural
language.

E.g., what is the role of the many instances of the character '#'? Those
instances are not in a natural language.

E.g., what is the token

'add1'?

That token is not in my Webster's dictionary, and I have been given no way to
parse it.

E.g.,

"increments items in an array matching specified value"

is not a sentence.

E.g., "param:" is not English.

Continuing, it is not clear what meant by an 'array'. So, we do not know the
value of the smallest subscript or the largest or how to determine these.

Next the terms

"from left-to-right (forward)"

and

"right-to-left (backward)"

are undefined and require a reader to guess. A careful guess would want to
know if the computer was big endian or little endian.

Finally, one might object to "most optimal" since, really, something is
'optimal' or it is not so that 'most' is superfluous.

Here is another way to start to write the problem statement:

Suppose you are given positive integer n, and suppose for i = 1, 2, ..., n,
you are given an integer x(i).

Etc.

Lesson: In computing, clear communications are important. Those communications
should be in a natural language, e.g., English.

My second remark would be to consider the part of the problem statement:

n < 0 means increment up to n occurrences of val from right-to-left (backward)

So, with this statement, if n < 0, then there is nothing to do since we cannot
do something a negative number of times.

So it appears that what was intended was:

n < 0 means increment up to -n occurrences of val from right-to-left
(backward)

~~~
sanderjd
You are being overly pedantic here.

One of the great things about two people from any reasonably mature field
communicating with each other is that they can take advantage of widely-
agreed-upon shorthand. Nearly everyone coming in for a programming interview
in 2012 will understand that the '#' character is often used for non-
executable program meta-data, that functions are often named with tokens such
as 'add1', that 'param:' typically means a function parameter with a
description of its value following the colon, what an 'array' is, how
subscripts work with them, and what is meant by the terms left-to-right,
forward, right-to-left, and backward (regardless of endian-ness, the inclusion
of which is sort of humorous since our hypothetical interviewee has, up to
this point, been assumed to be completely ignorant of programming-related
terms). You go on to suggest defining the problem in terms of short-hand from
a more mature, but less specifically relevant field, which I would argue would
actually be well understood by _fewer_ potential interviewees.

I do agree with you that it should probably be pointed out that the number of
occurrences should be stated as the absolute value of 'n', rather than just
'n', but this would become obvious very quickly when the candidate starts
asking clarification questions.

~~~
ten_fingers
I was trying to be simple, elementary, and easy to read! But my comment was
not at all "pedantic"!

Even with all the context you suggested, the problem statement is just not
very clear, and, in computing, computer science, and software, that lack of
clarity is not a small point.

Put more bluntly, there is no excuse, and in serious software, especially for
embedded systems, there is no role, for abbreviations that are on or over the
line into gibberish. You are correct that such gibberish is common in
software; my point is that we should not do that and should object.

Yes, in my suggested problem statement, I used notation common in mathematics.
Still, the math community still says that such writing is English. GOOD.

Here is a big point: Computer science, computing, and software have no good
substitute for such use of how mathematics is written. There is a partial
substitute in practice if assume a particular programming language.

The error of n instead of -n or the absolute value of n is small but is an
example of a huge point: A subroutine needs a description. A subroutine is
precisely something and should have a precise description. The problem here is
so simple we can get by with being imprecise as you suggest, but computing is
not limited to such simple routines, and the complicated ones also need
precise descriptions. Net, we need to write precise descriptions. Knuth did
this in TACP (yes, I abbreviate!); it really is possible.

For assuming that 'add1' means an argument 1 passed to a function add is
asking a lot even just in the context of software.

In passing a constant to a function there will be the issue, that should be
addressed, of passing 'by value' or 'by reference'. In Fortran a constant is
passed by reference with all the problems, side effects, and surprises there
unto appertaining! We can't yet assume that Fortran is buried!

If my work does well and I start to hire, I will give a lot of weight to
people who are good at reading and writing technical material and will prefer
that they know how to read and write abstract math. For learning Visual Basic
.NET, a book of code samples and a one week class should be able to do a lot.
Net, I'm questioning if I should require new hires for programming to know any
'computing' at all.

------
ten_fingers
Here is a solution in Microsoft's Visual Basic .NET making a little use of
some of .NET:

    
    
         ' ADD.VB --
         '
         ' Created at 21:34:59 on Wednesday, August 1st, 2012.
    
         '    Note:  There are some risks of fixed overflow
         '    depending on (1) the values of the components
         '    of arr() and (2) how the logic works for ending
         '    a For-Next loop in the case n is the largest
         '    value of Int32.
    
           Sub add( _
             arr() As Int32, _
             val As Int32, _
             n As Int32 )
    
           Dim arr_upper_bound As Int32
    
           Dim i As Int32
    
           Dim n_changes As Int32
    
         '    http://msdn.microsoft.com/en-us/library/system.array.getupperbound%28v=vs.100%29.aspx#Y104
    
           arr_upper_bound = arr.GetUpperBound( 0 )
    
         '    http://msdn.microsoft.com/en-us/library/cy37t14y(VS.80).aspx
    
           Select n
    
             Case n = 0
    
               For i = 0 To arr_upper_bound
    
                 If arr( i ) = val Then arr( i ) = arr( i ) + 1
    
               Next i
    
             Case n > 0
    
               n_changes = 0
    
               For i = 0 To arr_upper_bound
    
                 If arr( i ) = val Then
    
                   arr( i ) = arr( i ) + 1
    
                   n_changes = n_changes + 1
    
                   If n_changes = n Then Exit Select
    
                 End If
    
               Next i
    
             Case n < 0
    
               n_changes = 0
    
               For i = arr_upper_bound To 0 Step -1
    
                 If arr( i ) = val Then
    
                   arr( i ) = arr( i ) + 1
    
                   n_changes = n_changes + 1
    
                   If n_changes = -n Then Exit Select
    
                 End If
    
               Next i
    
           End Select
    
           Return
    
           End Sub

