1. Algorithm to Remove An Element Based on Value of Particular Element Position

Is there a super-fast, super-easy way to remove an element based on a value found at a particular element's position? For example:

sequence s = { {"1",1},{"2",2},{"3",3} } -- not actual data 
s = remove( s, 1, "1" } --<-- remove the element from sequence s whose first element equals "1" 
-- s is now { {"2",2},{"3",3} } 

I didn't find anything in the manual.

new topic     » topic index » view message » categorize

2. Re: Algorithm to Remove An Element Based on Value of Particular Element Position

that looks pretty easy, is there anything wrong with this?

function remove(sequence s, integer idx, object val) 
object si 
    for i=1 to length(s) do 
        si = s[i] 
        if sequence(si) and idx<=length(si) and equal(si[idx],val) then 
            s = s[1..i-1]&s[i+1..length(s)] 
            exit 
        end if 
    end for 
    return s 
end function 

Edit: oops - replaced equal(si[i],val) with equal(si[idx],val)
it should of course be renamed something like "remove_element_with_specified_ith_value()"

new topic     » goto parent     » topic index » view message » categorize

3. Re: Algorithm to Remove An Element Based on Value of Particular Element Position

petelomax said...

that looks pretty easy, is there anything wrong with this?

There's so much wrong with that code, but I don't have time to get into it.

HAHHAHAA! grin

Just kiddin'. I forgot about using 'exit' to break out. I was looping from end to beginning. Ugh.

Thanks!

new topic     » goto parent     » topic index » view message » categorize

4. Re: Algorithm to Remove An Element Based on Value of Particular Element Position

euphoric said...
petelomax said...

that looks pretty easy, is there anything wrong with this?

There's so much wrong with that code, but I don't have time to get into it.

HAHHAHAA! grin

Just kiddin'. I forgot about using 'exit' to break out. I was looping from end to beginning. Ugh.

Thanks!

That example code removes one element if it finds a match. Is it possible there might be more than one to be removed? This was kinda implied by the question but not stated outright. It's good to clarify these things..

Spock

new topic     » goto parent     » topic index » view message » categorize

5. Re: Algorithm to Remove An Element Based on Value of Particular Element Position

--** 
-- Removes an element from a sequence when that element contains the target 
-- 
-- Parameters: 
--	# ##Source## : a sequence to be checked for the target. 
--	# ##Target## : an object, the leftmost element containing this target value is removed. 
--      # ##Index## : an integer. If greater than zero, it specifies the index  
--                    at which the target must be found in the elements. If 
--                    zero, then the target can be found at any location in the 
--                    elements. 
-- 
-- Returns: 
-- A **sequence** that is identical the the source but without the leftmost 
-- element that had contained the target value. 
-- 
-- Comments: 
-- * This only removes, at most, one element.  
-- * All atom elements are ignored, and thus never removed. 
-- * If the target is not located, the original sequence is returned. 
-- 
-- Examples: 
-- <~eucode> 
-- -- The second element is removed because its first element is 3 
--  ? locate_remove({ {4,3}, {3,2}, {1}, 3}, 3, 1) --> { {4,3}, {1}, 3} 
-- sequence Data  
-- Data = { 
--          {"Bob","Carroll","Orange"}, 
--          {"Derek","Parnell","Blue"}, 
--          {"Iris","Lander","Red"} 
--        } 
-- -- Remove the element that contains "Parnell" as its second element. 
-- Data = locate_remove(Data, "Parnell", 2) 
-- ? Data -->  
-- --     { 
-- --         {"Bob","Carroll","Orange"}, 
-- --         {"Iris","Lander","Red"} 
-- --     } 
-- <~/eucode> 
 
public function locate_remove(sequence pSource, object pTarget, integer pIndex=1) 
	sequence lSample 
	-- Mild sanity check first. 
	if pIndex < 0 then 
		return pSource 
	end if 
	 
	-- Algorithm when the target must be at a specific location in the elements. 
	if pIndex >= 1 then	 
		-- Potentially need to check each element in the source parm. 
		for i = 1 to length(pSource) do 
			-- But only sequence elements 
			if sequence (pSource[i]) then 
				-- Take a reference copy for speed. Avoids multiple de-indexing. 
				lSample = pSource[i] 
				-- Only look at elements that can possibly contain the target. 
				if length(lSample) >= pIndex then 
					-- A simple equality test to check the that we have the target in this element. 
					if equal(pTarget, lSample[pIndex]) then 
						-- Shift remaining elements down, obliterating the element that 
						-- contains the target. This avoids duplicating the whole sequence. 
						pSource[i .. $-1] = pSource[i+1 .. $] 
						-- return the sequence minus the target, 
						-- and thus stop looking any more. 
						return pSource[1 .. $-1] 
					end if 
				end if 
			end if 
		end for 
		-- Didn't find the target anywhere, so return the source unchanged. 
		return pSource 
	end if 
	 
	-- Algorithm when the target can be anywhere in the elements. 
	 
	-- Potentially need to check each element in the source parm. 
	for i = 1 to length(pSource) do 
		-- But only sequence elements 
		if sequence (pSource[i]) then 
			-- Find the target in this element. 
			if find(pTarget, pSource[i]) != 0 then 
				-- Shift remaining elements down, obliterating the element that 
				-- contains the target. This avoids duplicating the whole sequence. 
				pSource[i .. $-1] = pSource[i+1 .. $] 
				-- return the sequence minus the target, 
				-- and thus stop looking any more. 
				return pSource[1 .. $-1] 
			end if 
		end if 
	end for 
	-- Didn't find the target anywhere, so return the source unchanged. 
	return pSource 
 
	 
end function 
 
-- Define the unit tests for this function. 
ifdef UNITTESTS then  -- Only invoke them if we are running with unit testing turned on. 
include std/unittest.e 
procedure _tester() 
sequence lBase 
 
	lBase = { {1}, {2,3}, 3, {3,4}, {}, {5,6,7}, {3,5} } 
 
	-- Stupid index parameter. 
	test_equal("A Low", lBase, locate_remove(lBase, 3, -1)) 
	test_equal("A High", lBase, locate_remove(lBase, 3, 9999999)) 
	 
	-- Specific index checks. 
	test_equal("B1", { {1}, {2,3}, 3, {}, {5,6,7}, {3,5} }, locate_remove(lBase, 3, 1)) 
	test_equal("B2", { {1}, {2,3}, 3, {}, {5,6,7}, {3,5} }, locate_remove(lBase, 3))  -- Use default index. 
	test_equal("C", { {1}, 3, {3,4}, {}, {5,6,7}, {3,5} }, locate_remove(lBase, 3, 2)) 
	test_equal("D", lBase, locate_remove(lBase, 3, 3)) 
	test_equal("E", lBase, locate_remove(lBase, -11)) 
	test_equal("F", lBase, locate_remove(lBase, `3`)) 
	test_equal("G", {}, locate_remove({}, 3)) 
	test_equal("H", { {1}, {2,3}, 3, {3,4}, {}, {3,5} }, locate_remove(lBase, 7, 3)) 
	 
	-- Target can be anywhere in the elements. 
	test_equal("I", { {1}, 3, {3,4}, {}, {5,6,7}, {3,5} },    locate_remove(lBase, 3, 0)) 
	test_equal("J", { {1}, 3, {3,4}, {}, {5,6,7}, {3,5} },    locate_remove(lBase, 2, 0)) 
	test_equal("K", { {2,3}, 3, {3,4}, {}, {5,6,7}, {3,5} },  locate_remove(lBase, 1, 0)) 
	test_equal("L", { {1}, {2,3}, 3, {3,4}, {}, {3,5} },      locate_remove(lBase, 7, 0)) 
	test_equal("M", lBase, locate_remove(lBase, 0, 0)) 
	 
end procedure 
_tester() 
test_report() 
 
 
end ifdef 
new topic     » goto parent     » topic index » view message » categorize

6. Re: Algorithm to Remove An Element Based on Value of Particular Element Position

Spock said...

That example code removes one element if it finds a match. Is it possible there might be more than one to be removed? This was kinda implied by the question but not stated outright. It's good to clarify these things..

Maybe I'm over-thinking things, but here's my take on the algorithm...

public constant 
    LT = -1,        -- less than 
    EQ =  0,        -- equal to 
    GT =  1,        -- greater than 
    NE = {LT,GT},   -- not equal to 
$ 
 
-- 
-- Remove items from 's' where s[n][index] is 'ops' (e.g. EQ) to 'value'. 
-- 
-- Note: to compare the whole item, set 'index' to 0. 
-- 
public function remove_where( sequence s, integer index, object value, object ops = EQ, integer limit = 0 ) 
     
    integer n, count, cmp, op1, op2 
     
    n = 1 
    count = 0 
     
    if atom( ops ) then 
        op1 = ops 
        op2 = ops 
    else 
        op1 = ops[1] 
        op2 = ops[2] 
    end if 
     
    while n <= length( s ) do 
         
        if atom( s[n] ) or length( s[n] ) < index then 
            -- skip invalid items 
            n += 1 
            continue 
        end if 
         
        if index = 0 then 
            -- compare the whole item 
            cmp = compare( s[n], value ) 
        else 
            -- compare the index of item 
            cmp = compare( s[n][index], value ) 
        end if 
         
        if cmp = op1 or cmp = op2 then 
             
            -- remove the matching item 
            s = remove( s, n ) 
             
            count += 1 
            if count = limit then 
                -- stop processing 
                exit 
            end if 
             
        else 
            -- move to the next item 
            n += 1 
             
        end if 
         
    end while 
     
    return s 
end function 

Example:

include std/console.e 
 
sequence s = { 
    {"1",1}, 
    {"2",2}, 
    {"3",3}, 
    {"4",4}, 
    {"5",5}, 
    {"6",6} 
} 
 
-- remove any item starting with "1" 
s = remove_where( s, 1, "1" ) 
display( s ) 
 
-- remove the first item less than or equal to "3" 
s = remove_where( s, 1, "3", {LT,EQ}, 1 ) 
display( s ) 
 
-- remove everything not equal to "4" 
s = remove_where( s, 1, "4", {LT,GT}, 0 ) 
display( s ) 

Output:

{ 
  {"2",2}, 
  {"3",3}, 
  {"4",4}, 
  {"5",5}, 
  {"6",6} 
} 
{ 
  {"3",3}, 
  {"4",4}, 
  {"5",5}, 
  {"6",6} 
} 
{ 
  {"4",4} 
} 

-Greg

new topic     » goto parent     » topic index » view message » categorize

7. Re: Algorithm to Remove An Element Based on Value of Particular Element Position

ghaberek said...

Maybe I'm over-thinking things, but here's my take on the algorithm...

DerekParnell said...
--** 
-- Removes an element from a sequence when that element contains the target 
-- 
-- Parameters: 
--	# ##Source## : a sequence to be checked for the target. 
--	# ##Target## : an object, the leftmost element containing this target value is removed. 
--      # ##Index## : an integer. If greater than zero, it specifies the index  
--                    at which the target must be found in the elements. If 
--                    zero, then the target can be found at any location in the 
--                    elements. 
-- 
-- Returns: 
-- A **sequence** that is identical the the source but without the leftmost 
-- element that had contained the target value. 
-- 
-- Comments: 
-- * This only removes, at most, one element.  
-- * All atom elements are ignored, and thus never removed. 
-- * If the target is not located, the original sequence is returned. 
-- 
-- Examples: 
-- <~eucode> 
-- -- The second element is removed because its first element is 3 
--  ? locate_remove({ {4,3}, {3,2}, {1}, 3}, 3, 1) --> { {4,3}, {1}, 3} 
-- sequence Data  
-- Data = { 
--          {"Bob","Carroll","Orange"}, 
--          {"Derek","Parnell","Blue"}, 
--          {"Iris","Lander","Red"} 
--        } 
-- -- Remove the element that contains "Parnell" as its second element. 
-- Data = locate_remove(Data, "Parnell", 2) 
-- ? Data -->  
-- --     { 
-- --         {"Bob","Carroll","Orange"}, 
-- --         {"Iris","Lander","Red"} 
-- --     } 
-- <~/eucode> 

I guess I'm not over-thinking this; Derek's code certainly looks more impressive. My code will process atom items (set index = 0 to compare atoms) plus it will compare items of any given equality (e.g. less than).

-Greg

new topic     » goto parent     » topic index » view message » categorize

8. Re: Algorithm to Remove An Element Based on Value of Particular Element Position

Spock said...

That example code removes one element if it finds a match. Is it possible there might be more than one to be removed? This was kinda implied by the question but not stated outright. It's good to clarify these things..

In my particular use-case, there would only ever be one matching record. However, you're right. There might be a need to eliminate all records matching the criteria.

Thank you for the additional code, Derek and Greg! And everybody else who has contributed or will contribute. smile

new topic     » goto parent     » topic index » view message » categorize

9. Re: Algorithm to Remove An Element Based on Value of Particular Element Position

Would this work ?

sequence s s = { {"1",1},{"2",2},{"3",3} } 
 
function Remove( object o, sequence seq ) 
-- 
atom p 
-- 
if atom( o ) then 
p = find(o,seq) 
else 
p = match(o,seq) 
endif 
-- 
if not p then 
  return seq 
elsif p = 1 then 
  return seq[1+sizeof(o)-1..$] 
else 
  return seq[1..p-1]&seq[+1+sizeof(o)..$] 
end if 
end function 
new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu