python -- apply/run script for every array instance individually
Distribute copies.
Further to @moonboots answer can copy and distribute the object. Each copy shares the one mesh.
import bpy
from mathutils import Vector
from random import uniform


def array(context, count, rel_offset=Vector(), rnd_var_range=(0, 0), rnd_var_dir=Vector()):
    scene = context.scene
    for ob in context.selected_objects:
        mw = ob.matrix_world
        R = mw.to_quaternion().to_matrix()
        offset =  R * rel_offset.dot(ob.dimensions) * rel_offset.normalized()
        copies = count - 1
       
        for i in range(copies):
            copy = ob.copy()
            t = copy.matrix_world.translation
            t  += (i + 1) * offset            
            copy.delta_location = uniform(*rnd_var_range) * rnd_var_dir
            copy.select = True
            scene.objects.link(copy)

# test call

context = bpy.context

array(context, 
    count = 5,
    rel_offset = Vector((1.1 , 0, 0)),
    rnd_var_dir = Vector((0, 1, 0)),
    rnd_var_range = (-1, 1))
    
array(context, 
    count = 5,
    rel_offset = Vector((0, 0, 1.1)),
    rnd_var_dir = Vector((0, 1, 0)),
    rnd_var_range = (-1, 1))


Result of running script with Suzanne selected. The variation of both arrays in test call are in local Y direction.
The same script updated to Blender 2.8 API
import bpy
from mathutils import Vector
from random import uniform


def array(context, count, rel_offset=Vector(), rnd_var_range=(0, 0), rnd_var_dir=Vector()):
    scene = context.scene
    for ob in context.selected_objects:
        mw = ob.matrix_world
        R = mw.to_quaternion().to_matrix()
        offset =  R @ (rel_offset.dot(ob.dimensions) * rel_offset.normalized())
        copies = count - 1

        for i in range(copies):
            copy = ob.copy()
            t = copy.matrix_world.translation
            t  += (i + 1) * offset            
            copy.delta_location = uniform(*rnd_var_range) * rnd_var_dir
            context.collection.objects.link(copy)
            copy.select_set(state=True)
            context.view_layer.objects.active = copy
            
           
            

# test call

context = bpy.context

array(context, 
    count = 5,
    rel_offset = Vector((1.1 , 0, 0)),
    rnd_var_dir = Vector((0, 1, 0)),
    rnd_var_range = (-1, 1))

array(context, 
    count = 5,
    rel_offset = Vector((0, 0, 1.1)),
    rnd_var_dir = Vector((0, 1, 0)),
    rnd_var_range = (-1, 1))

Main changes are:

@ operator is now used for matrix/vector component-wise multiplication
selection of an object in context is now done with copy.select_set(state=True)
The link must now be done via collections and not view_layer