diff --git a/comfort-array.cabal b/comfort-array.cabal
--- a/comfort-array.cabal
+++ b/comfort-array.cabal
@@ -1,5 +1,5 @@
 Name:             comfort-array
-Version:          0.3
+Version:          0.3.1
 License:          BSD3
 License-File:     LICENSE
 Author:           Henning Thielemann <haskell@henning-thielemann.de>
@@ -33,9 +33,6 @@
     E.g. a non-negative index type like 'Word' cannot represent @-1@
     and thus cannot encode an empty range starting with index @0@.
   .
-  * @Square@:
-    An 2D array where both dimensions always have equal size.
-  .
   * @ZeroBased, OneBased@:
     Arrays with fixed lower bound, either 0 or 1, respectively.
   .
@@ -43,8 +40,12 @@
     The Append type constructor allows to respresent block arrays,
     e.g. block matrices.
   .
-  * Arrays with indices like 'LT', 'EQ', 'GT' and dummy shape.
+  * @Enumeration@: Arrays with indices like 'LT', 'EQ', 'GT' and dummy shape.
   .
+  * @Set@: Use an arbitrary ordered set as index set.
+  .
+  * @Triangular@: A 2D array with the shape of lower or upper triangular matrix.
+  .
   The @lapack@ package defines even more fancy shapes
   like tall rectangular matrices, triangular matrices and banded matrices.
 
@@ -55,7 +56,7 @@
   Changes.md
 
 Source-Repository this
-  Tag:         0.3
+  Tag:         0.3.1
   Type:        darcs
   Location:    http://hub.darcs.net/thielema/comfort-array/
 
@@ -63,6 +64,10 @@
   Type:        darcs
   Location:    http://hub.darcs.net/thielema/comfort-array/
 
+Flag setIndex
+  Description: Use efficient Set indexing from containers>=0.5.4
+  Default:     True
+
 Library
   Build-Depends:
     primitive >=0.6.4 && <0.7,
@@ -70,11 +75,18 @@
     storable-record >=0.0.1 && <0.1,
     deepseq >=1.3 && <1.5,
     QuickCheck >=2 && <3,
+    containers >=0.4 && <0.7,
     transformers >=0.3 && <0.6,
     non-empty >=0.3 && <0.4,
     utility-ht >=0.0.10 && <0.1,
     base >=4.5 && <5
 
+  If flag(setIndex)
+    Build-Depends: containers >=0.5.4
+    Hs-Source-Dirs: set/0.5.4
+  Else
+    Hs-Source-Dirs: set/0.4.0
+
   GHC-Options:      -Wall
   Default-Language: Haskell98
   Hs-Source-Dirs:   src
@@ -90,12 +102,15 @@
     Data.Array.Comfort.Storable.Mutable.Private
     Data.Array.Comfort.Boxed
   Other-Modules:
+    Data.Array.Comfort.Shape.Set
+    Data.Array.Comfort.Shape.Utility
     Data.Array.Comfort.Boxed.Unchecked
 
 Test-Suite comfort-array-test
   Type: exitcode-stdio-1.0
   Build-Depends:
     comfort-array,
+    containers,
     QuickCheck,
     base
 
diff --git a/set/0.4.0/Data/Array/Comfort/Shape/Set.hs b/set/0.4.0/Data/Array/Comfort/Shape/Set.hs
new file mode 100644
--- /dev/null
+++ b/set/0.4.0/Data/Array/Comfort/Shape/Set.hs
@@ -0,0 +1,31 @@
+module Data.Array.Comfort.Shape.Set where
+
+import Data.Array.Comfort.Shape.Utility (errorIndexFromOffset)
+
+import qualified Data.Set as Set
+import Data.Set (Set)
+import Data.Tuple.HT (fst3)
+
+
+offset :: Ord a => Set a -> a -> Int
+offset set ix =
+   case Set.splitMember ix set of
+      (less, hit, _) ->
+         if hit
+            then Set.size less
+            else error "Shape.Set: array index not member of the index set"
+
+uncheckedOffset :: Ord a => Set a -> a -> Int
+uncheckedOffset set = Set.size . fst3 . flip Set.splitMember set
+
+indexFromOffset :: Set a -> Int -> a
+indexFromOffset set k =
+   if 0<=k
+      then uncheckedIndexFromOffset set k
+      else errorIndexFromOffset "Set" k
+
+uncheckedIndexFromOffset :: Set a -> Int -> a
+uncheckedIndexFromOffset set k =
+   case drop k $ Set.toAscList set of
+      [] -> errorIndexFromOffset "Set" k
+      ix:_ -> ix
diff --git a/set/0.5.4/Data/Array/Comfort/Shape/Set.hs b/set/0.5.4/Data/Array/Comfort/Shape/Set.hs
new file mode 100644
--- /dev/null
+++ b/set/0.5.4/Data/Array/Comfort/Shape/Set.hs
@@ -0,0 +1,13 @@
+module Data.Array.Comfort.Shape.Set where
+
+import qualified Data.Set as Set
+import Data.Set (Set)
+
+
+offset, uncheckedOffset :: Ord a => Set a -> a -> Int
+offset = flip Set.findIndex
+uncheckedOffset = offset
+
+indexFromOffset, uncheckedIndexFromOffset :: Set a -> Int -> a
+indexFromOffset = flip Set.elemAt
+uncheckedIndexFromOffset = indexFromOffset
diff --git a/src/Data/Array/Comfort/Boxed.hs b/src/Data/Array/Comfort/Boxed.hs
--- a/src/Data/Array/Comfort/Boxed.hs
+++ b/src/Data/Array/Comfort/Boxed.hs
@@ -5,7 +5,9 @@
    Array.toList,
    toAssociations,
    Array.fromList,
+   fromMap,
    Array.vectorFromList,
+   indices,
 
    Array.map,
    zipWith,
@@ -24,6 +26,9 @@
 import Control.Monad.ST (runST)
 import Control.Applicative ((<$>))
 
+import qualified Data.Map as Map
+import Data.Map (Map)
+import Data.Set (Set)
 import Data.Foldable (forM_)
 
 import Prelude hiding (zipWith)
@@ -31,6 +36,13 @@
 
 shape :: Array.Array sh a -> sh
 shape = Array.shape
+
+
+indices :: (Shape.Indexed sh) => sh -> Array.Array sh (Shape.Index sh)
+indices sh = Array.fromList sh $ Shape.indices sh
+
+fromMap :: (Ord k) => Map k a -> Array (Set k) a
+fromMap m = Array.fromList (Map.keysSet m) (Map.elems m)
 
 
 infixl 9 !
diff --git a/src/Data/Array/Comfort/Shape.hs b/src/Data/Array/Comfort/Shape.hs
--- a/src/Data/Array/Comfort/Shape.hs
+++ b/src/Data/Array/Comfort/Shape.hs
@@ -21,6 +21,9 @@
    triangleSize, triangleRoot,
    ) where
 
+import qualified Data.Array.Comfort.Shape.Set as ShapeSet
+import Data.Array.Comfort.Shape.Utility (errorIndexFromOffset)
+
 import qualified Foreign.Storable.Newtype as Store
 import Foreign.Storable
          (Storable, sizeOf, alignment, poke, peek, pokeElemOff, peekElemOff)
@@ -35,9 +38,9 @@
 import Control.Applicative (Applicative, pure, liftA2, liftA3, (<*>))
 import Control.Applicative (Const(Const, getConst))
 
-import Text.Printf (printf)
-
+import qualified Data.Set as Set
 import qualified Data.NonEmpty as NonEmpty
+import Data.Set (Set)
 import Data.List.HT (tails)
 import Data.Tuple.HT (mapSnd, mapPair, swap, fst3, snd3, thd3)
 
@@ -77,11 +80,7 @@
    uncheckedIndexFromOffset :: sh -> Int -> Index sh
    uncheckedIndexFromOffset = indexFromOffset
 
-errorIndexFromOffset :: String -> Int -> a
-errorIndexFromOffset name k =
-   error $ printf "indexFromOffset (%s): index %d out of range" name k
 
-
 instance C () where
    size () = 1
    uncheckedSize () = 1
@@ -301,7 +300,7 @@
 {- |
 'Enumeration' denotes a shape of fixed size
 that is defined by 'Enum' and 'Bounded' methods.
-For correctness it is necessary that the 'Enum' and 'Bounded'
+For correctness it is necessary that the 'Enum' and 'Bounded' instances
 are properly implemented.
 Automatically derived instances are fine.
 -}
@@ -344,6 +343,26 @@
    alignment ~Enumeration = 1
    poke _p Enumeration = return ()
    peek _p = return Enumeration
+
+
+{- |
+You can use an arbitrary 'Set' of indices as shape.
+The array elements are ordered according to the index order in the 'Set'.
+-}
+instance (Ord n) => C (Set n) where
+   size = uncheckedSize
+   uncheckedSize = Set.size
+
+instance (Ord n) => Indexed (Set n) where
+   type Index (Set n) = n
+   indices = Set.toAscList
+   offset = ShapeSet.offset
+   uncheckedOffset = ShapeSet.uncheckedOffset
+   inBounds = flip Set.member
+
+instance (Ord n) => InvIndexed (Set n) where
+   indexFromOffset = ShapeSet.indexFromOffset
+   uncheckedIndexFromOffset = ShapeSet.uncheckedIndexFromOffset
 
 
 {- |
diff --git a/src/Data/Array/Comfort/Shape/Utility.hs b/src/Data/Array/Comfort/Shape/Utility.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Array/Comfort/Shape/Utility.hs
@@ -0,0 +1,8 @@
+module Data.Array.Comfort.Shape.Utility where
+
+import Text.Printf (printf)
+
+
+errorIndexFromOffset :: String -> Int -> a
+errorIndexFromOffset name k =
+   error $ printf "indexFromOffset (%s): index %d out of range" name k
diff --git a/src/Data/Array/Comfort/Storable.hs b/src/Data/Array/Comfort/Storable.hs
--- a/src/Data/Array/Comfort/Storable.hs
+++ b/src/Data/Array/Comfort/Storable.hs
@@ -6,8 +6,12 @@
 
    (!),
    Array.toList,
-   Array.fromList,
+   fromList,
+   fromMap,
    Array.vectorFromList,
+   sample,
+   fromBoxed,
+   toBoxed,
 
    Array.map,
    Array.mapWithIndex,
@@ -19,6 +23,7 @@
 import qualified Data.Array.Comfort.Storable.Mutable.Unchecked as MutArrayNC
 import qualified Data.Array.Comfort.Storable.Mutable as MutArray
 import qualified Data.Array.Comfort.Storable.Unchecked as Array
+import qualified Data.Array.Comfort.Boxed as BoxedArray
 import qualified Data.Array.Comfort.Shape as Shape
 import Data.Array.Comfort.Storable.Unchecked (Array)
 
@@ -26,6 +31,10 @@
 
 import Control.Monad.ST (runST)
 
+import qualified Data.Map as Map
+import qualified Data.List as List
+import Data.Map (Map)
+import Data.Set (Set)
 import Data.Foldable (forM_)
 
 import Text.Printf (printf)
@@ -51,6 +60,24 @@
 mapShape ::
    (Shape.C sh0, Shape.C sh1) => (sh0 -> sh1) -> Array sh0 a -> Array sh1 a
 mapShape f arr = reshape (f $ shape arr) arr
+
+
+fromList :: (Shape.C sh, Storable a) => sh -> [a] -> Array sh a
+fromList sh arr = runST (MutArrayNC.unsafeFreeze =<< MutArray.fromList sh arr)
+
+fromMap :: (Ord k, Storable a) => Map k a -> Array (Set k) a
+fromMap m = fromList (Map.keysSet m) (Map.elems m)
+
+sample ::
+   (Shape.Indexed sh, Storable a) => sh -> (Shape.Index sh -> a) -> Array sh a
+sample sh f = Array.fromList sh $ List.map f $ Shape.indices sh
+
+
+fromBoxed :: (Shape.C sh, Storable a) => BoxedArray.Array sh a -> Array sh a
+fromBoxed arr = Array.fromList (BoxedArray.shape arr) $ BoxedArray.toList arr
+
+toBoxed :: (Shape.C sh, Storable a) => Array sh a -> BoxedArray.Array sh a
+toBoxed arr = BoxedArray.fromList (Array.shape arr) $ Array.toList arr
 
 
 infixl 9 !
diff --git a/test/Test/Shape.hs b/test/Test/Shape.hs
--- a/test/Test/Shape.hs
+++ b/test/Test/Shape.hs
@@ -9,7 +9,9 @@
 
 import Control.Applicative (liftA2, liftA3)
 
+import qualified Data.Set as Set
 
+
 genZeroBased :: Int -> QC.Gen (Shape.ZeroBased Int)
 genZeroBased n = fmap Shape.ZeroBased $ QC.choose (0,n)
 
@@ -34,6 +36,9 @@
    prefix "Enumeration Ordering"
       (ShapeTest.tests $
        return (Shape.Enumeration :: Shape.Enumeration Ordering)) ++
+   prefix "Set"
+      (ShapeTest.tests $
+       fmap Set.fromList (QC.listOf (QC.choose ('a','z')))) ++
    prefix "Deferred Shifted"
       (ShapeTest.tests $ fmap Shape.Deferred $
        liftA2 Shape.Shifted
