Reputation: 149
I have this list:
[[0,4,1,4],[1,12,1,4],[2,8,1,4],[3,54,2,4],[4,1,2,2]]
I also have another list: [2,3]
-- Represents the indexes i want to get from each sublist
Output should be like:
[[1,4],[1,4],[1,4],[2,4],[2,2]]
Another example:
List :
[[0,4,1,4],[1,12,1,4],[2,8,1,4],[3,54,2,4],[4,1,2,2]]
Indexes : [0,2,3]
Output should be like:
[[0,1,4],[1,1,4],[2,1,4],[3,2,4],[4,2,2]]
Upvotes: 3
Views: 336
Reputation: 7014
If the elements are always 4-tuples consider using a specialized type for it (Linear.V4
)
type V4 :: Type -> Type
data V4 a = V4 a a a a
along with an indexing type that gives total indexing, because we know V4
has a static size (this is because V4
is a Representable
functor):
type Fin4 :: Type
data Fin4 = Fin0 | Fin1 | Fin2 | Fin3
infixl 9 !!!
(!!!) :: V4 a -> Fin4 -> a
V4 a _ _ _ !!! Fin0 = a
V4 _ a _ _ !!! Fin1 = a
V4 _ _ a _ !!! Fin2 = a
V4 _ _ _ a !!! Fin3 = a
This is enough to define slices
using Willem's definition
slices :: [Fin4] -> [V4 a] -> [[a]]
slices is = map ((`map` is) . (!!!))
>> slices [Fin2, Fin3] example
[[1,4],[1,4],[1,4],[2,4],[2,2]]
>> slices [Fin0, Fin2, Fin3] example
[[0,1,4],[1,1,4],[2,1,4],[3,2,4],[4,2,2]]
This can be generalized for vectors of any length
type N :: Type
data N = O | S N
infixr 5 :>
type Vec :: N -> Type -> Type
data Vec n a where
VNil :: Vec O a
(:>) :: a -> Vec n a -> Vec (S n) a
deriving stock
instance Show a => Show (Vec n a)
deriving stock
instance Functor (Vec n)
type Fin :: N -> Type
data Fin n where
FinO :: Fin (S n)
FinS :: Fin n -> Fin (S n)
infixl 9 !!!
(!!!) :: Vec n a -> Fin n -> a
VNil !!! fin = case fin of
(a:>as) !!! FinO = a
(a:>as) !!! FinS fin = as !!! fin
slices :: [Fin n] -> [Vec n a] -> [[a]]
slices = ..
example :: [Vec (S (S (S (S O)))) Int]
example =
[ 0:>4:>1:>4:>VNil
, 1:>12:>1:>4:>VNil
, 2:>8:>1:>4:>VNil
, 3:>54:>2:>4:>VNil
, 4:>1:>2:>2:>VNil
]
Indices and lists of tuples can be generalized to work for any functor
slices :: Functor f => Functor g => f (Fin n) -> g (Vec n b) -> g (f b)
slices is = fmap ((`fmap` is) . (!!!))
If we treat the list of examples as an 5-ary vector
example :: Vec (S (S (S (S (S O))))) (Vec (S (S (S (S O)))) Int)
example
= (0:>4:>1:>4:>VNil)
:> (1:>12:>1:>4:>VNil)
:> (2:>8:>1:>4:>VNil)
:> (3:>54:>2:>4:>VNil)
:> (4:>1:>2:>2:>VNil)
:> VNil
>> slices (FinS (FinS FinO) :> FinS (FinS (FinS FinO)) :> VNil) example
(1 :> 4 :> VNil)
:> (1 :> 4 :> VNil)
:> (1 :> 4 :> VNil)
:> (2 :> 4 :> VNil)
:> (2 :> 2 :> VNil)
:> VNil
Upvotes: 1
Reputation: 476584
You obtain the item in a list with a given index with (!!) :: [a] -> Int -> a
, for example:
Prelude> [0,4,1,4] !! 0
0
Prelude> [0,4,1,4] !! 2
1
Prelude> [0,4,1,4] !! 3
4
We thus can perform a mapping to obtain the items for a list of items:
Prelude> map ([0,4,1,4] !!) [0,2,3]
[0,1,4]
we thus can slice a list of lists with:
slices :: [Int] -> [[a]] -> [[a]]
slices is = map ((`map` is) . (!!))
For example:
Prelude> slices [0,2,3] [[0,4,1,4],[1,12,1,4],[2,8,1,4],[3,54,2,4],[4,1,2,2]]
[[0,1,4],[1,1,4],[2,1,4],[3,2,4],[4,2,2]]
Using (!!)
is however unsafe: it is not guaranteed that a list has an element with the given index, furthermore, it is not very efficient: it takes O(k) to obtain the k-th element. Therefore it is better to work with Vector
or an Array
and with lookups that return a Nothing
when the index is out of range, for example for a Vector
, we can use (!?) :: Vector a -> Int -> Maybe a
.
Upvotes: 3