Link to home
Start Free TrialLog in
Avatar of arcrotty
arcrotty

asked on

Comparing arrays with arrays

I need a way to compare arrays with other arrays.  These are generally arrays of ordinal values.  I'd like to add arrays to arrays, compare to see if all items in first array are in second, and remove items from an array from an array.  I've looked at SETS and it looks like it has some of what I need, but lacks the ability to add and remove items.

function InArray(A:array of Byte; B:array of Byte) : Boolean;

returning true if all items in array A are in B.  Note: There can be duplicates of the same value and if there are, there has to be atleast that many in array B to return TRUE.

function AddArray(A:array of Byte; B : Array of Byte): array of byte;

function SubtractArray(A:array of Byte;B:array of byte): array of bytw

I could generally write these myself, but I was wondering if there was a package out there that was already written that could do this.

It could be done either using dynamic/variant arrays or Tlist, it don't matter, but I need a way to COUNT the members in the array and access the data so I can save it to a stream.  It should also not require too much CPU resources because it is going to be called many times.

If someone can point me to a link that will help me I'll give 200 points, if someone goes thru the trouble and writes it themselves or posts/emails me the exact functions I need, I'll give 400+ points.  I have 1200 available.

This is for an online game that is similiar to a MUD, but it is graphical.  It is for the slots system to keep track of how many of each bodypart are not equipping anything.

If you want to help out, with the game project.  Let me know.  We need graphics artists and programmers.  We curretnly have 4 people on it.
Avatar of Epsylon
Epsylon

Look in the Delphi help (index tab) for 'set operators'. Maybe that opens a whole new world for you.
The only problem when using sets are duplicate values...
Avatar of arcrotty

ASKER

Duplicate values are a big thing.  Is there an undocumented method of checking all the values in the set?  Or is it prolly stored in a bit array of boolean or something.

basically I need to compare things like:
 
[1,1,1] in [1,1,1,2,2] = true;
[1,1,1] in [1,2,2,2] = false;
[1,1,2] + [1,2,3,4] = [1,1,1,2,2,3,4]
[1,2,2,3,4] - [2,3] = [1,2,4]

not necessarily in any specific order... but can be.  All the values will be an ordinal value.  An easy way to do this would be to have an array and make each dimension of it a count of each value, but this would use up a lot of memory (256 bytes) and there is going to be a lot of objects using these arrays in the order of prolly 1000's and would require a for 0..255 loop during each check even if there is only one item in the list.

In the program I'm writing, there prolly won't be more then 16 different ordinal values and generally the max will be about 4 of each.  They will represent body parts of types of creatures.  A human has 2 legs, minotours have 4, etc.  It basically is used to keep track of what slots are available to armor.  If a helmet is to be worn, it checks to see if there is a S_HEAD slot available, and if so, removes that slot from the list.  When it is taken off, it puts it back on the availability list.  Some weapons require 2 hands and would require 2 S_HAND slots.


I just had a thought...

If I set hard limits ...

S_HAND = 1;       // 0000000000000001
S_HAND_SHIFT = 0; // 0000000000000111
S_HAND_MAX = 7 SHL S_HAND_SHIFT;

S_ARM = 8;        // 0000000000001000
S_ARM_SHIFT = 3;  // 0000000000111000
S_ARM_MAX = 7 SHL S_ARM_SHIFT;

S_HEAD = 64;      // 0000000001000000
S_HEAD_SHIFT = 6; // 0000000011000000
S_HEAD_MAX = 3 SHL S_HEAD_SHIFT;

S_TWO_HANDS := S_HAND+S_HAND;

This method looks like it works well except for the fact that I will run out of bits fast.  Is there a way to shift a multi-byte block of data?  A 64 bit number *might* be big enough for my purposes.  I'm just thinking on the fly.

SlotsReq := S_HAND + S_ARM;
SlotsAvail := S_HAND + S_HAND + S_ARM + S_ARM + S_HEAD + etc...

NumHands = (SlotsAvail AND S_HAND_MAX) SHR S_HAND_SHIFT;

If SlotsReq OR SlotsAvail = SlotsAvail then; // there is enough slots.

This looks like an effient way of doing it, but I need a way to shift possible a 128-bit number if it exists.
I've not the time to write this completely for you, but I've some hints for you:

I recommend using dynamic arrays (only possible in D4 and D5). Sets are quite limited, because they can't hold the same value twice.

First of all, declare an array type like this:

type
  TYourOrdinalArray = array of integer;

Now the functions should look like this:

function InArray(const A, B: TYourOrdinalArray) : boolean;
var i1 : integer;
begin
  if length(A) <= length(B) then begin
    // here comes the big loop test
  end else
    result := false;
end;


function AddArray(const A, B: TYourOrdinalArray) : TYourOrdinalArray;
var i1, i2, i3 : integer;
begin
  i1 := Length(A);
  i2 := Length(B);
  SetLength(result, i1 + i2);
  for i3 := 0 to i1 - 1 do
    result[i3] := A[i3];
  for i3 := 0 to i2 - 1 do
    result[i1 + i3] := B[i3];
end;

function SubstractArray(const A, B: TYourOrdinalArray) : TYourOrdinalArray;
begin
  // ...
end;

Saving to a stream works like this:

  stream.Write(pointer(arr)^, Length(arr) * 4);  // *4 for integer; *1 for byte

Regards, Madshi.
P.S: AddArray should be complete.
1) When looking at this definition you gave us in your question, who do you tell the function how many element the arrays have?

function AddArray(A:array of Byte; B : Array of Byte): array of byte


2) Array of byte means that the array can contain values from 0 to 255. Is it possible to use 0 for special purposes, e.g. a sentinel?
ASKER CERTIFIED SOLUTION
Avatar of Epsylon
Epsylon

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Adjusted points to 375
Madshi,

You examples were real good, but epsilon's was a bit more complete.  I wish I could split the points, but...


Epsilon,

I was looking for a more memory efficient way of doing things, but you made up for it in detail.  I've increased the points to 375 for your help.
Epsilon,

Looking at the code more closely I noticed that I'd need to create your Tarrayset for each array.  I really needed to compare generic arrays, not a new Tarrayset.  I'll see if I can do that for you.  If you want to make it more complete for yourself, you should add clear() to it.  I'm going to be making these changes myself, if you want me to send you my changes, let me know.
>Looking at the code more closely I noticed that I'd need to create your Tarrayset for each array.

You can do that if you want but you can choose only to create them when you need them. This way it uses much less memory of course.

Btw: when handling large or unsorted arrays, TArraySet is very fast...


>I'm going to be making these changes myself, if you want me to send you my changes, let me know.

Please do  :o)


Cheers,

Epsylon.

I may still have your email address somewhere from the last time you helped me.  But incase I don't, email me at smorales@twinlab.com.