리스트(list)는 맥시마의 기본 자료형 중 하나로서 다양한 표현식을 하나의 집합으로 묶어놓은 것이다. 기본적인 정의는 대괄호 [ ] 를 이용하며 각각의 요소는 콤마(,)로 구분한다. (공백 문자가 아님에 주의하자.)



위의 예는 lsA라는 변수에 리스트 [1, 2, 7, x+y]를 대입한 것이다. 리스트명은 임의의 식별자가 될 수 있다. 만약 x나 y가 어떤 값을 갖는 변수라면 그 값이 대신 들어간다. 그렇지 않다면 그냥 문자 상수로 인식된다.


 리스트 내부의 하나의 요소를 참조할 때에는 리스트명 뒤에 역시 대괄호를 이용하여 인덱스를 지정한다.



리스트의 요소로는 표현식(상수, 변수, 수학 함수 등등)과 리스트 자체도 리스트의 요소가 될 수 있다. 다음 예를 보자.



lsA는 네 개의 요소를 갖는 리스트인데 네 번째 요소는 리스트이다. 따라서 lsA[4]는 리스트 [a,b,c]인 것이다. 리스트 안의 리스트를 인덱싱하기 위해서는 위의 마지막 예와 같이 하면 된다.


 만약 값을 가진 변수를 이용하여 리스트를 정의한 후에 사용된 변수의 값을 바꾸면 어떻게 될까? 변경된 값이 리스트에 영향을 미칠까? 다음 예를 살펴보자.



만약 위와 같이 변수 a, b값을 이용하여 lsA를 정의했다면 정의된 그 시점의 a, b값이 lsA에 사용되는 것이지 변수 a, b 자체를 사용한 것은 아니다. 따라서 이후에 변수 a, b값을 바꾸는 것은 lsA에 아무런 영향을 미치지 않는다는 사실에 유의해야 한다.



그리고 리스트와 스칼라와의 산술 연산은 리스트 내의 모든 요소에 적용된다.



그리고 리스트끼리의 산술연산은 크기가 똑같아야 성립된다.



 리스트를 다루는 여러 함수 중에 많이 사용되는 몇 개만 소개하면 다음과 같다. 먼저 append() 함수는 두개의 리스트를 입력받아서 그 두개를 붙인 리스트를 생성한다.



리스트의 크기를 구하는 함수로서 length() 함수가 있다.



그리고 첫 번째 요소와 마지막 요소를 반환하는 함수는 각각 first(), last() 함수이다.



[표 1] 리스트 관련 함수 정리

기호

의미

append(lsA, lsB)

lsA와 lsB를 붙여서 새로운 리스트 생성

length(lsA)

lsA의 요소의 개수를 반환

first(lsA)

lsA의 첫 번째 요소

last(lsA)

lsA의 마지막 요소




Posted by 살레시오

댓글을 달아 주세요

 자바 제네릭(generic) 프로그래밍에 대해서 실습하던 중에 제네닉 타입의 단순 배열을 생성하는데 미묘하게 안 되는게 있기도 해서 구글링을 해 보았더니 배열을 쓰지말고 웬만하면 List<>를 사용하는게 여러 모로 편하다고 하는 의견들이 많았다. 성능차도 별로 없다고 해서 직접 간단한 프로그램으로 실행 시간을 측정 해보기로 하였다..


 초기에 크기는 배열과 리스트 모두 정해졌다고 가정하고 단순 읽고 쓰는 속도만 비교하였다.


package listtestj01;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class ListTestj01 {
   public static    long iter = 1000000L;
   public static    int id;
   public static    double db, dSum;
   public static long le, ls;

   public static Double[] dArr;
   public static List<Double> lst;

   public static void main(String[] args) {
       dArr = new Double[100];
       for(int k=0;k<100;k++) dArr[k]=new Double(1.0);
       
       lst = new ArrayList<>();
       for(int k=0;k<100;k++) lst.add(new Double(1.0));

       doIt();
       doIt();
       doIt();
   }
   
   public static void doIt() {
       double dSum1 =0, dSum2=0;
       long id;
       for(int n=0;n<10;n++) {
           
           ls = System.nanoTime();
           for(int k=0;k<iter;k++)
               for(int x=0;x<100;x++) {
                   db=dArr[x];
                   dArr[x]=db;
               }
           le = System.nanoTime();
           dSum1 += (le-ls)/1e9;

           ls = System.nanoTime();
           for(int k=0;k<iter;k++)
               for(int x=0;x<100;x++) {
                   db = lst.get(x);
                   lst.set(x, db);
               }
           le = System.nanoTime();
           dSum2 += (le-ls)/1e9;
        }
       System.out.println("Double Arr: "+dSum1/10+ "sec.");
       System.out.println("List<Doub>: "+dSum2/10+ "sec.");
   }
}


이 예에서 붉은 색으로 마킹된 부분을 보면 단순히 배열 요소에서 하나를 읽고 다시 하나를 쓰고를 1억번 반복하고 이것을 다시 열 번 반복해서 평균시간을 구해서 비교하는 것이다. 내 노트북(윈764비트)에서 다음과 같은 결과를 얻었다.



세 번 반복해서 재 보아도 모두 단순 배열쪽이 두 배 이상 속도가 빨랐다. 리스트가 느리더라도 그 차이가 많이 안 나길 기대했는데 이것으로 적어도 대규모 연산이 있는 곳에서는 단순 배열이 속도 면에서 훨씬 더 낫다는 (당연한) 결과를 얻었다.




Posted by 살레시오

댓글을 달아 주세요

 리스트는 여러 개의 객체를 하나로 묶는 데이터 형이다. (엄밀히 말하면 mutable sequence 형임) 기본적으로 대괄호 [..]를 이용하여 묶고자 하는 데이터들을 콤마(,)로 구별하여 나열한다. 보통은 같은 형의 데이터를 묶어서 많이 사용하지만 리스트의 요소는 서로 다른 데이터 형일 수 있다.


>>> la = [11, 22, 33] # 리스트를 생성하여 la 에 저장한다.
>>> lb = [‘life’, ‘is’, ‘short’] # 문자열의 리스트
>>> lc = [True, ‘hi’, 33.4, 2-3j]
>>> ld = [] # empty list를 생성하여 lc에 저장


이 예제와 같이 리스트의 요소는 어떠한 자료형이라도 가능하다. 리스트 안에 리스트가 오는 것도 얼마든지 가능하다.


>>> le = [ [11,22], [33, 44, 55] ]


이것을 중첩된 리스트라고 한다.


리스트를 만드는 또 다른 방법은 list comprehension 을 이용하는 것이다. 예를 들어서 제곱 수의 리스트틀 만든다고 가정하자. 다음과 같이 for 문을 이용할 수 도 있을 것이다.


>>> squares = []
>>> for x in range(10):
...    squares.append(x**2)
...
>>> squares
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]


하지만 이 방법은 변수 x가 생성되고 for 문이 종료된 후에도 변수 x 가 메모리에 남아 있게 된다. 좀 더 깔끔한 방법은 다음과 같이 map()과 익명 함수를 이용하는 것이다.


>>> squares = list(map(lambda x: x**2, range(10)))


이것과 완전히 동일한 방법이 바로 다음과같은 list comprehension 이고 훨씬 더 간결하고 가독성이 높다.


>>> squares = [x**2 for x in range(10)]


일반적으로 다음과 같이 구성된다.


[ 표현식 for문 (for 문 | if 문)* ]


예를 들어서 두 리스트 요소 중 다른 것들로만 조합하는 리스트는 다음과 같다.


>>> [(x,y) for x in [1,2,3] for y in [3,1,4] if x!=y]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]


이것은 다음 프로그램과 동일한 동작을 수행한다.


>>> combs = []
>>> for x in [1,2,3]:
...    for y in [3,1,4]:
...        if x != y:
...            combs.append((x, y))
...
>>> combs
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]


두 가지 경우에서 for 문과 if 문의 순서가 같다는 것을 알 수 있다.

표현식이 튜플일 경우 반드시 괄호로 묶어야 한다.


>>> [(x,x**2) for x in range(6)]
[(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25)]


만약 다음과 같이 괄호를 생략하면 에러가 발생한다.


>>> [ x,x**2  for x in range(6)] # 에러 발생


여기서 소개한 내용이 리스트를 생성하는 기본적인 방법들이다.



Posted by 살레시오

댓글을 달아 주세요