Skip to main content
Known Participant
April 1, 2015
Answered

is there any equivalent of the operator "known" for an arrary?

  • April 1, 2015
  • 2 replies
  • 1059 views

I would like to know if an element of an array is available and its index so that I can get it. I can do it for a dictionary with the "known" operator. Is there anything that is equivalent for an array? 

This topic has been closed for replies.
Correct answer jdeubert

Hi.

I know of no built-in function that does this in PostScript. However, some years back I cooked up something equivalent.

I had an array of values (all unique, which is necessary for this technique to work) that I had to repeatedly process sequentially, but *only* if the array contained a particular value already. What I did was set up a “shadow dictionary” that had as its keys the values from the array, each key associated with the index of that value in the array. (See code below.)

To determine whether a value was in the array, I could do a “known” on the dictionary. Very much faster than a sequential search of the array.

Note that this technique depends on a little-known characteristic of PostScript dictionaries: a dictionary key can be any type of PS object, not just a name or string.

Also note that this technique increases the memory use of the code. A classic case of memory versus speed.

Finally, if all you really want is the position of the object in the array (which was not my case way back when), you don’t really need the array at all. Just use the dictionary with each object (formerly in the array) associated with the appropriate “index” value.

Hope this helps.

- John

===============

Acumen Training

PostScript & PDF

Consulting & Training

www.acumentraining.com

===============

% ======== Cut Here ==================

% The array

/theArray [ 100 27 19 -6 42.8 (Bunny) ] def

% The shadow dict

/theDict theArray length dict def

theDict begin

% Load the dict with the array's values

0 1 theArray length 1 sub {

  theArray 1 index get

  exch def

} for

end

% This procedure determines whether an object is a member of theArray

% and, if so, returns the object’s index and true; otherwise it returns a false.

/ArrayKnown { % obj => i  true  |  false

  theDict exch

  2 copy known

  { get true }{ pop false }

  ifelse

} bind def

% Now let's try this puppy out...

100 ArrayKnown  { = } {(Not here.) = } ifelse

(Bunny) ArrayKnown   { = } {(Not here.) = } ifelse

/TweedleDee ArrayKnown   { = } {(Not here.) = } ifelse

2 replies

PS-InterpAuthor
Known Participant
April 2, 2015

Hi John,

There seems to be one problem if the element in the array is an dictionary.

I replaced the integer 27 with <</Hi (World)>> and <</Hi (World)>> ArrayKnown could not find it.

Is this an intrinsic PostScript limitation or is it just a programing issue?

Participating Frequently
April 2, 2015

Hmmm. This wasn't an issue in my original project. It's a PostScript thing.

Dictionaries and arrays (and also strings, but they are special-cased) are implemented as "composite objects," whose values are references to places in memory where the actual values (key-value pairs in the case of a dictionary) are stored. The dictionary you placed into the shadow dictionary contained a reference to a particular place in memory. When you say

<</Hi (World)>> ArrayKnown

you have constructed a new dictionary and a pointer to a different, newly-allocated piece of memory; the contents are identical to the original, but they're stored in a different place in memory. The "known" operator, when it compares keys, only looks at the memory reference for composite objects (with one exception: strings are special-cased). Thus, "known" doesn't see this as a match.

I can't think of any simple workaround for this that doesn't involve something nasty, recursive, and brute-force; these would also be slow and so aren't probably worth doing.

Unfortunately, any comparison of arrays or dictionaries will run into the same problem. Consider the following two-line snippet:

    <</Hi(World)>>  <</Hi(World)>>  eq ==

   <</Hi(World)>>  dup  eq ==

The first line returns false, because you are comparing two different dictionaries that happen to have identical contents. The second returns true because the dup operator copies the object that's on the operand stack, including its reference to memory; we are comparing two copies of identical references, so eq returns true.

The technique used in ArrayKnown will work only with Simple objects (numbers, booleans, etc.), strings (which are special cased), and names. (It'll work with a few other object types, also, including operator objects and file objects, but using those as keys is behavior bordering on aberrant.

- J

PS-InterpAuthor
Known Participant
April 2, 2015

Again, awesome answer. I appreciate it.

Robert

PS: If it is possible, would you take a look at my recent question of finding glyphs of a downloaded CID font?

jdeubertCorrect answer
Participating Frequently
April 2, 2015

Hi.

I know of no built-in function that does this in PostScript. However, some years back I cooked up something equivalent.

I had an array of values (all unique, which is necessary for this technique to work) that I had to repeatedly process sequentially, but *only* if the array contained a particular value already. What I did was set up a “shadow dictionary” that had as its keys the values from the array, each key associated with the index of that value in the array. (See code below.)

To determine whether a value was in the array, I could do a “known” on the dictionary. Very much faster than a sequential search of the array.

Note that this technique depends on a little-known characteristic of PostScript dictionaries: a dictionary key can be any type of PS object, not just a name or string.

Also note that this technique increases the memory use of the code. A classic case of memory versus speed.

Finally, if all you really want is the position of the object in the array (which was not my case way back when), you don’t really need the array at all. Just use the dictionary with each object (formerly in the array) associated with the appropriate “index” value.

Hope this helps.

- John

===============

Acumen Training

PostScript & PDF

Consulting & Training

www.acumentraining.com

===============

% ======== Cut Here ==================

% The array

/theArray [ 100 27 19 -6 42.8 (Bunny) ] def

% The shadow dict

/theDict theArray length dict def

theDict begin

% Load the dict with the array's values

0 1 theArray length 1 sub {

  theArray 1 index get

  exch def

} for

end

% This procedure determines whether an object is a member of theArray

% and, if so, returns the object’s index and true; otherwise it returns a false.

/ArrayKnown { % obj => i  true  |  false

  theDict exch

  2 copy known

  { get true }{ pop false }

  ifelse

} bind def

% Now let's try this puppy out...

100 ArrayKnown  { = } {(Not here.) = } ifelse

(Bunny) ArrayKnown   { = } {(Not here.) = } ifelse

/TweedleDee ArrayKnown   { = } {(Not here.) = } ifelse

PS-InterpAuthor
Known Participant
April 2, 2015

Thank you so very much John. It's a brilliant idea. Search for a character in a string can employ the same technique.