Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Set operations



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------------------------------



Messages sorted by: Reverse Date, Date, Thread, Author