목록에서 n 번째 요소를 어떻게 얻을 수 있습니까?
이 C 코드와 유사한 Haskell의 인덱스로 목록에 액세스하려면 어떻게해야합니까?
int a[] = { 34, 45, 56 };
return a[1];
봐 여기 , 연산자를 !!
.
즉 , 목록이 0 인덱싱되기 때문에 [1,2,3]!!1
제공합니다 2
.
질문이나 답변에 문제가 있다고 말하는 것이 아닙니다 . 미래에 시간을 절약 할 수있는 Hoogle 의 멋진 도구에 대해 알고 싶을 수도 있습니다. Hoogle 을 사용하면 표준 라이브러리 기능을 검색 할 수 있습니다. 주어진 서명과 일치합니다. 따라서에 대해 아무것도 알지 못하는 !!
경우 "무엇 Int
이든 목록 을 가져 와서 하나를 반환하는 것"을 검색 할 수 있습니다 . 즉
Int -> [a] -> a
Lo 및 behold , !!
첫 번째 결과로 (유형 서명에는 실제로 검색 한 것과 비교하여 두 개의 인수가 반대로 있음) 깔끔 하죠?
또한 코드가 목록의 맨 앞에서 소비하는 대신 인덱싱에 의존하는 경우 목록이 실제로 적절한 데이터 구조가 아닐 수 있습니다. O (1) 인덱스 기반 액세스의 경우 배열 또는 벡터 와 같은보다 효율적인 대안이 있습니다 .
사용에 대한 대안 (!!)
은 렌즈 패키지와 그 element
기능 및 관련 작업자를 사용하는 것입니다. 렌즈 위에 나열 이후 구조 및 중첩 구조의 다양한 액세스 균일 한 인터페이스를 제공한다. 아래에서는 예제를 제공하는 데 중점을두고 유형 서명과 렌즈 패키지 의 이론에 대해 설명 합니다. 이론에 대해 더 알고 싶다면 github repo에 있는 readme 파일을 시작하는 것이 좋습니다 .
목록 및 기타 데이터 유형에 액세스
렌즈 패키지에 액세스하기
명령 줄에서 :
$ cabal install lens
$ ghci
GHCi, version 7.6.3: http://www.haskell.org/ghc/ :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
> import Control.Lens
목록에 액세스
중위 연산자로 목록에 액세스하려면
> [1,2,3,4,5] ^? element 2 -- 0 based indexing
Just 3
이와 달리 (!!)
경계를 벗어난 요소에 액세스 할 때 예외가 발생하지 Nothing
않고 대신 반환 됩니다. 코너 케이스가 더 많고 런타임 오류가 발생할 가능성이 더 높기 때문에 (!!)
또는 같은 부분 기능을 피하는 것이 좋습니다 head
. 이 위키 페이지 에서 부분 기능을 피해야하는 이유에 대해 조금 더 읽을 수 있습니다 .
> [1,2,3] !! 9
*** Exception: Prelude.(!!): index too large
> [1,2,3] ^? element 9
Nothing
렌즈 기술을 부분 함수로 강제하고 (^?!)
연산자 대신 연산자를 사용하여 범위를 벗어난 경우 예외를 throw 할 (^?)
수 있습니다.
> [1,2,3] ^?! element 1
2
> [1,2,3] ^?! element 9
*** Exception: (^?!): empty Fold
목록 이외의 유형 작업
그러나 이것은 목록에만 국한되지 않습니다. 예를 들어 동일한 기술 이 표준 컨테이너 패키지의 트리 에서 작동 합니다.
> import Data.Tree
> :{
let
tree = Node 1 [
Node 2 [Node 4[], Node 5 []]
, Node 3 [Node 6 [], Node 7 []]
]
:}
> putStrLn . drawTree . fmap show $tree
1
|
+- 2
| |
| +- 4
| |
| `- 5
|
`- 3
|
+- 6
|
`- 7
We can now access the elements of the tree in depth-first order:
> tree ^? element 0
Just 1
> tree ^? element 1
Just 2
> tree ^? element 2
Just 4
> tree ^? element 3
Just 5
> tree ^? element 4
Just 3
> tree ^? element 5
Just 6
> tree ^? element 6
Just 7
We can also access sequences from the containers package:
> import qualified Data.Sequence as Seq
> Seq.fromList [1,2,3,4] ^? element 3
Just 4
We can access the standard int indexed arrays from the vector package, text from the standard text package, bytestrings fro the standard bytestring package, and many other standard data structures. This standard method of access can be extended to your personal data structures by making them an instance of the typeclass Taversable, see a longer list of example Traversables in the Lens documentation..
Nested structures
Digging down into nested structures is simple with the lens hackage. For example accessing an element in a list of lists:
> [[1,2,3],[4,5,6]] ^? element 0 . element 1
Just 2
> [[1,2,3],[4,5,6]] ^? element 1 . element 2
Just 6
This composition works even when the nested data structures are of different types. So for example if I had a list of trees:
> :{
let
tree = Node 1 [
Node 2 []
, Node 3 []
]
:}
> putStrLn . drawTree . fmap show $ tree
1
|
+- 2
|
`- 3
> :{
let
listOfTrees = [ tree
, fmap (*2) tree -- All tree elements times 2
, fmap (*3) tree -- All tree elements times 3
]
:}
> listOfTrees ^? element 1 . element 0
Just 2
> listOfTrees ^? element 1 . element 1
Just 4
You can nest arbitrarily deeply with arbitrary types as long as they meet the Traversable
requirement. So accessing a list of trees of sequences of text is no sweat.
Changing the nth element
A common operation in many languages is to assign to an indexed position in an array. In python you might:
>>> a = [1,2,3,4,5]
>>> a[3] = 9
>>> a
[1, 2, 3, 9, 5]
The lens package gives this functionality with the (.~)
operator. Though unlike in python the original list is not mutated, rather a new list is returned.
> let a = [1,2,3,4,5]
> a & element 3 .~ 9
[1,2,3,9,5]
> a
[1,2,3,4,5]
element 3 .~ 9
is just a function and the (&)
operator, part of the lens package, is just reverse function application. Here it is with the more common function application.
> (element 3 .~ 9) [1,2,3,4,5]
[1,2,3,9,5]
Assignment again works perfectly fine with arbitrary nesting of Traversable
s.
> [[1,2,3],[4,5,6]] & element 0 . element 1 .~ 9
[[1,9,3],[4,5,6]]
The straight answer was already given: Use !!
.
However newbies often tend to overuse this operator, which is expensive in Haskell (because you work on single linked lists, not on arrays). There are several useful techniques to avoid this, the easiest one is using zip. If you write zip ["foo","bar","baz"] [0..]
, you get a new list with the indices "attached" to each element in a pair: [("foo",0),("bar",1),("baz",2)]
, which is often exactly what you need.
Haskell's standard list data type forall t. [t]
in implementation closely resembles a canonical C linked list, and shares its essentially properties. Linked lists are very different from arrays. Most notably, access by index is a O(n) linear-, instead of a O(1) constant-time operation.
If you require frequent random access, consider the Data.Array
standard.
!!
is an unsafe partially defined function, provoking a crash for out-of-range indices. Be aware that the standard library contains some such partial functions (head
, last
, etc.). For safety, use an option type Maybe
, or the Safe
module.
Example of a reasonably efficient, robust total (for indices ≥ 0) indexing function:
data Maybe a = Nothing | Just a
lookup :: Int -> [a] -> Maybe a
lookup _ [] = Nothing
lookup 0 (x : _) = Just x
lookup i (_ : xs) = lookup (i - 1) xs
Working with linked lists, often ordinals are convenient:
nth :: Int -> [a] -> Maybe a
nth _ [] = Nothing
nth 1 (x : _) = Just x
nth n (_ : xs) = nth (n - 1) xs
You can use !!
, but if you want to do it recursively then below is one way to do it:
dataAt :: Int -> [a] -> a
dataAt _ [] = error "Empty List!"
dataAt y (x:xs) | y <= 0 = x
| otherwise = dataAt (y-1) xs
참고URL : https://stackoverflow.com/questions/5217171/how-can-i-get-nth-element-from-a-list
'development' 카테고리의 다른 글
return myVar와 return (myVar) 사이에 차이점이 있습니까? (0) | 2020.09.10 |
---|---|
날짜 만 표시하고 시간은 표시하지 않음 (0) | 2020.09.10 |
부모 클래스 (정적 컨텍스트)에서 자식 클래스의 이름 가져 오기 (0) | 2020.09.10 |
Python의 임의 해시 (0) | 2020.09.10 |
Paramiko를 사용하여 SSH 반환 코드를 어떻게 얻을 수 있습니까? (0) | 2020.09.10 |