Never been to DZone Snippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

« Newer Snippets
Older Snippets »
Showing 1-2 of 2 total  RSS 

Treating first/last loop iterations differently

Sometimes, you need to iterate over a list of items and treat the first and last element differently from the rest. This tends to produce really messy code, which can be avoided using the following snippet.

Imagine you have a list of Kittens, and you want to print out a summary of them, saying "My kittens are called Bob, James, John, and Ally." You need to treat the first and last element of the list differently from the rest, lest you end up with superfluous commas in the text. You also need to deal with the cases of there being only one kitten, or no kittens at all.

To do this, you can avail yourself of a Counter class that keeps track of where you are in the iteration:
String kittenDesc = "I have no kittens.";
Counter kc = new Counter(kittens);
for (Kitten k : kittens) switch(kc.next()) {
	case one:   kittenDesc =  "My kitten is called " + k.getName() + "."; break;
	case first: kittenDesc =  "My kittens are called " + k.getName();     break;
	case item:  kittenDesc += ", " + k.getName();                         break;
	case last:  kittenDesc += " and " + k.getName() + ".";                break;
}

package com.zarkonnen.util;

import java.util.Collection;

/**
 * Used for keeping track of where you are in a collection/array being iterated over. Use by
 * initialising with the collection/array before the loop and embedding a switch on the next() Mode
 * value into the loop.
 *
 * LICENCE: This code is licenced under a BSD licence. Feel free to alter and redistribute.
 *
 * @author David Stark, http://www.zarkonnen.com
 * @version 1.0 (2007-07-11)
 */
public class Counter {
	/**
	 * An enumeration of modes identifying where in the collection/array we are.
	 */
	public enum Where {
		/** The only element of an array/collection of size 1. */ one,
		/** The first element. */                                 first,
		/** The last element of the array/collection. */          last,
		/** Any other element somewhere in the middle. */         item
	}
	
	private int size;
	private int nextIndex = 0;
	
	/**
	 * @param c A collection to keep track of. If its size changes between now and the
	 * iteration, strange things will happen.
	 */
	public Counter(Collection c) {
		size = c.size();
	}
	
	/**
	 * @param a An array to keep track of. If its size changes between now and the iteration,
	 * strange things will happen.
	 */
	public Counter(Object[] a) {
		size = a.length;
	}
	
	/**
	 * @return A Where enum value for where in the array/collection we now are:
	 * <ul>
	 * <li><strong>one</strong> at the only element of an array/collection of size 1</li>
	 * <li><strong>first</strong> at the first element</li>
	 * <li><strong>last</strong> at the last element</li>
	 * <li><strong>item</strong> at any other element</li>
	 * </ul>
	 */
	public Where next() {
		return size == 1         ? Where.one   :
		       nextIndex++ == 0  ? Where.first :
		       nextIndex == size ? Where.last  :
		                           Where.item  ;
	}
	
	/**
	 * @return Which index of the array/collection we're currently at.
	 */
	public int index() {
		return nextIndex == 0 ? 0 : nextIndex - 1;
	}
}

Lua: Descending Table Traversal Round 2: Iterator Object

This is some concept code I threw together for Lua to see how feasable it was to make a lua object/table into an iterator that you can manipulate. This iterator descends through all tables and subtables of any queued table. It returns the "path" we're at, as a string, the current table, the key, and the value.

Code:
traverse = {}
function traverse:new(tname)
	local o = {}
	o.names = {}
	o.queue = {}
	o.cur = {
		tbl = nil,
		path = nil,
		state = nil,
	}

	local mt = {}
	function mt:__call(tn)
		return o:iter(tn)
	end
	mt.__index = self
	setmetatable(o, mt)

	if tname then
		o:enqueue(tname)
	end
	return o
end
function traverse:next()
	local v
	local names, queue, cur = self.names, self.queue, self.cur

	local function _poptbl()
		if cur.tbl then
			names[cur.tbl] = nil
		end
		cur.tbl = table.remove(queue, 1)
		cur.path = names[cur.tbl]
		cur.state = nil
	end

	repeat
		-- Find something to return to the user...
		if not cur.state then
			-- Pop a new table off the stack
			_poptbl()
			if not cur.tbl then
				-- No more tables to process
				return nil
			end
		end
		cur.state,v = next(cur.tbl, cur.state)
	until cur.state

	if type(v) == "table" then
		local path = cur.path.."."..cur.state
		names[v] = path
		table.insert(queue, v)
	end
	return cur.path,cur.tbl,cur.state,v
end
function traverse:iter(tname)
	if tname then
		self:enqueue(tname)
	end
	return function(...) return self:next(unpack(arg)) end, nil, nil
end
function traverse:enqueue(tname)
	local v = _G[tname]
	table.insert(self.queue, v)
	self.names[v] = tname
end
function traverse:reset()
	self.names = {}
	self.queue = {}
end
local traverse_mt = {
    __call = function(self, tname)
             	if tname then
             		return self:new(tname):iter()
             	else
             		return self:new()
             	end
             end
}
setmetatable(traverse, traverse_mt)


Example Usage:
foo = {a={},b={},c={"bar"},d={e={},f={"moo"}},1,2,3,4,5}
bar = {"alpha", "beta", "theta", omega = {}}

local mytraverser = traverse()
mytraverser:enqueue("bar")
mytraverser:enqueue("foo")
for p,t,k,v in mytraverser() do
--for p,t,k,v in traverse('foo') do
	print(string.format("%s[%s] = %s",tostring(p),tostring(k),tostring(v)))
end


Output from Example Usage:
bar[1] = alpha
bar[2] = beta
bar[3] = theta
bar[omega] = table: 0x510650
foo[1] = 1
foo[2] = 2
foo[3] = 3
foo[4] = 4
foo[5] = 5
foo[a] = table: 0x5102d0
foo[c] = table: 0x510370
foo[b] = table: 0x510320
foo[d] = table: 0x5103c0
foo.c[1] = bar
foo.d[e] = table: 0x5104c0
foo.d[f] = table: 0x510510
foo.d.f[1] = moo
« Newer Snippets
Older Snippets »
Showing 1-2 of 2 total  RSS