zsh-workers
 help / color / mirror / code / Atom feed
From: Phil Pennock <zsh-workers+phil.pennock@spodhuis.org>
To: Zsh hackers list <zsh-workers@sunsite.dk>
Subject: Set operations
Date: Sat, 27 Sep 2008 02:02:25 -0700	[thread overview]
Message-ID: <20080927090225.GA61785@redoubt.spodhuis.org> (raw)

Somehow, until a recent post from Bart, I'd missed ${array:#element} to
remove an element from an array.  That was the clean removal method I'd
been missing for using -U unique arrays as sets.

So the below is a first pass implementation of set arithmetic; however,
the safesub stuff shows that my big problem is, when joining existing
elements together with |, escaping pattern-characters in the original
array elements.  It does try to be fairly resistant to non-normal
setups without going full emulate, since it only uses a few features.

So given 'b' naming the set variable with the elements to remove, I do a
first pass approximation like this:

safesub=("${(@)${(@)${(@)${(P@)b//\\/\\\\}//\|/\\|}//\?/\\?}//\*/\\*}")

instead of just, for set subtraction of b from a:

  "${(P@)a:#${(Pj,|,)~b}}"

However, this obviously doesn't deal with the full set of
pattern-matching characters, so is incomplete.

So, before I head off and implement a parameter expansion flag to escape
pattern-matching characters (honouring current pattern-affecting
options), the question is whether I'm missing something obvious to do
this set arithmetic cleanly already, or if there's already a clean way
to escape pattern characters?

Any feedback on the complete set (so to speak) of functionality or
naming or implementation appreciated, with an eye to adding this to the
standard zsh install (autoloaded function set_operations to define
these?)

Or is the thing to do to overload the arithmetic operations in
arithmetic expansion, for let, to be able to handle -U arrays as sets
natively?  :-)  (let diff=a-b ...)

(The number of times I work with large lists of machines interactively
in shell and want to deal with them as sets and manipulate appropriately
is somewhat high and I'm fed up of switching to Python.)

Regards,
-Phil

#----------------------------8< cut here >8------------------------------
function newset {
	setopt local_options no_ksh_arrays
	local name="$1"; shift
	typeset -gUa $name
	set -A $name "$@"
}

function copyset_tofrom {
	setopt local_options no_ksh_arrays
	local new="$1" old="$2"
	typeset -gUa $new
	set -A $new "${(P@)old}"
}
function copyset_fromto { copyset_tofrom "$2" "$1" }

function set_add_new {
	setopt local_options no_ksh_arrays
	local new="$1" a="$2" b="$3"
	typeset -gUa $new
	set -A $new "${(P@)a}" "${(P@)b}"
}

function set_add_in {
	setopt local_options no_ksh_arrays
	local name="$1" b="$2"
	set -A $name "${(P@)name}" "${(P@)b}"
}

function set_add_print {
	setopt local_options no_ksh_arrays
	local a="$1" b="$2"
	typeset -Ua tmp
	tmp=("${(P@)a}" "${(P@)b}")
	print -r -- ${(q)tmp}
}

function set_subtract_new {
	setopt local_options no_ksh_arrays
	local new="$1" a="$2" b="$3"
	typeset -gUa $new
	typeset -Ua safesub
	safesub=("${(@)${(@)${(@)${(P@)b//\\/\\\\}//\|/\\|}//\?/\\?}//\*/\\*}")
	set -A $new "${(P@)a:#${(j,|,)~safesub}}"
}

function set_subtract_in {
	setopt local_options no_ksh_arrays
	local name="$1" b="$2"
	typeset -Ua safesub
	safesub=("${(@)${(@)${(@)${(P@)b//\\/\\\\}//\|/\\|}//\?/\\?}//\*/\\*}")
	set -A $name "${(P@)name:#${(j,|,)~safesub}}"
}

function set_subtract_print {
	setopt local_options no_ksh_arrays
	local a="$1" b="$2"
	typeset -Ua tmp
	typeset -Ua safesub
	safesub=("${(@)${(@)${(@)${(P@)b//\\/\\\\}//\|/\\|}//\?/\\?}//\*/\\*}")
	tmp=("${(P@)a:#${(j,|,)~safesub}}")
	print -r -- ${(q)tmp}
}

function set_intersection_new {
	setopt local_options no_ksh_arrays
	local new="$1" a="$2" b="$3"
	typeset -gUa $new
	typeset -Ua safesub
	safesub=("${(@)${(@)${(@)${(P@)b//\\/\\\\}//\|/\\|}//\?/\\?}//\*/\\*}")
	set -A $new "${(@PM)a:#${(j,|,)~safesub}}"
}

function set_union_new { set_add_new "$@" }
function set_union_in { set_add_in "$@" }
function set_union_print { set_add_print "$@" }

function set_difference_new { set_subtract_new "$@" }
function set_difference_in { set_subtract_in "$@" }
function set_difference_print { set_subtract_print "$@" }

function set_symmetric_difference_new {
	setopt local_options no_ksh_arrays
	local new="$1" a="$2" b="$3"
	typeset -gUa $new
	typeset -Ua safe_a safe_b
	safe_b=("${(@)${(@)${(@)${(P@)a//\\/\\\\}//\|/\\|}//\?/\\?}//\*/\\*}")
	safe_b=("${(@)${(@)${(@)${(P@)b//\\/\\\\}//\|/\\|}//\?/\\?}//\*/\\*}")
	set -A $new "${(P@)a:#${(j,|,)~safe_b}}" "${(P@)b:#${(j,|,)~safe_a}}"
}

function set_symmetric_difference_in {
	setopt local_options no_ksh_arrays
	local name="$1" b="$2"
	typeset -Ua safe_name safe_b
	safe_a=("${(@)${(@)${(@)${(P@)a//\\/\\\\}//\|/\\|}//\?/\\?}//\*/\\*}")
	safe_b=("${(@)${(@)${(@)${(P@)b//\\/\\\\}//\|/\\|}//\?/\\?}//\*/\\*}")
	set -A $name "${(P@)name:#${(j,|,)~safe_b}}" "${(P@)b:#${(j,|,)~safe_name}}"
}

function set_symmetric_difference_print {
	setopt local_options no_ksh_arrays
	local a="$1" b="$2"
	typeset -Ua tmp
	typeset -Ua safe_a safe_b
	safe_b=("${(@)${(@)${(@)${(P@)a//\\/\\\\}//\|/\\|}//\?/\\?}//\*/\\*}")
	safe_b=("${(@)${(@)${(@)${(P@)b//\\/\\\\}//\|/\\|}//\?/\\?}//\*/\\*}")
	tmp=("${(P@)a:#${(j,|,)~safe_b}}" "${(P@)b:#${(j,|,)~safe_a}}")
	print -r -- ${(q)tmp}
}

function set_insert_list {
	setopt local_options no_ksh_arrays
	local name="$1"; shift
	set -A $name "${(P@)name}" "$@"
}

function set_remove_list {
	setopt local_options no_ksh_arrays
	local name="$1"; shift
	typeset -Ua safesub
	safesub=("${(@)${(@)${(@)${(P)@//\\/\\\\}//\|/\\|}//\?/\\?}//\*/\\*}")
	set -A $name "${(P@)name:#${(j,|,)~safesub}}"
}
#----------------------------8< cut here >8------------------------------


             reply	other threads:[~2008-09-27  9:03 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-09-27  9:02 Phil Pennock [this message]
2008-09-27 20:48 ` Peter Stephenson
2008-09-28  1:50   ` Phil Pennock

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20080927090225.GA61785@redoubt.spodhuis.org \
    --to=zsh-workers+phil.pennock@spodhuis.org \
    --cc=zsh-workers@sunsite.dk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).