Bash 배열에서 요소 제거


116

bash 셸의 배열에서 요소를 제거해야합니다. 일반적으로 간단히 다음을 수행합니다.

array=("${(@)array:#<element to remove>}")

불행히도 제거하려는 요소는 변수이므로 이전 명령을 사용할 수 없습니다. 여기에 예가 있습니다.

array+=(pluto)
array+=(pippo)
delete=(pluto)
array( ${array[@]/$delete} ) -> but clearly doesn't work because of {}

어떤 생각?


어떤 껍질? 귀하의 예는 다음과 같습니다 zsh.
chepner 2013 년

array=( ${array[@]/$delete} )Bash에서 예상대로 작동합니다. 단순히 놓친 적이 =있습니까?
Ken Sharp

1
@Ken, 그것은 원하는 것이 아닙니다. 각 문자열에서 일치하는 항목을 제거하고 전체 문자열과 일치하는 배열에 빈 문자열을 남겨 둡니다.
Toby Speight 2019

답변:


165

다음은 bash및 에서 원하는대로 작동합니다 zsh.

$ array=(pluto pippo)
$ delete=pluto
$ echo ${array[@]/$delete}
pippo
$ array=( "${array[@]/$delete}" ) #Quotes when working with strings

둘 이상의 요소를 삭제해야하는 경우 :

...
$ delete=(pluto pippo)
for del in ${delete[@]}
do
   array=("${array[@]/$del}") #Quotes when working with strings
done

경고

이 기술은 실제로 $delete전체 요소가 아니라 요소에서 일치하는 접두사를 제거합니다 .

최신 정보

정확한 항목을 실제로 제거하려면 배열을 살펴보고 대상을 각 요소와 비교하고을 사용 unset하여 정확히 일치하는 항목을 삭제해야합니다.

array=(pluto pippo bob)
delete=(pippo)
for target in "${delete[@]}"; do
  for i in "${!array[@]}"; do
    if [[ ${array[i]} = $target ]]; then
      unset 'array[i]'
    fi
  done
done

이 작업을 수행하고 하나 이상의 요소가 제거되면 인덱스는 더 이상 연속적인 정수 시퀀스가 ​​아닙니다.

$ declare -p array
declare -a array=([0]="pluto" [2]="bob")

단순한 사실은 배열이 가변 데이터 구조로 사용하도록 설계되지 않았다는 것입니다. 이들은 주로 구분 기호로 문자를 낭비하지 않고 단일 변수에 항목 목록을 저장하는 데 사용됩니다 (예 : 공백을 포함 할 수있는 문자열 목록 저장).

간격이 문제가되는 경우 간격을 채우기 위해 배열을 다시 빌드해야합니다.

for i in "${!array[@]}"; do
    new_array+=( "${array[i]}" )
done
array=("${new_array[@]}")
unset new_array

43
: 그냥 알고 $ array=(sun sunflower) $ delete=(sun) $ echo ${array[@]/$delete}결과flower
번스타인

12
배열이 같은 것입니다 그렇다면,이 실제로 대체를하고 있습니다 (pluto1 pluto2 pippo)다음으로 끝날 것이다 (1 2 pippo).
haridsv 2014 년

5
삭제 된 요소가 있던 곳에 빈 요소로 끝날 것이기 때문에 for 루프에서 이것을 사용하는 데주의하십시오. 온전함을 위해 당신은 다음과 같이 할 수 있습니다for element in "${array[@]}" do if [[ $element ]]; then echo ${element} fi done
Joel B

2
그렇다면 일치하는 요소 만 삭제하는 방법은 무엇입니까?
UmaN

4
참고 : 이렇게하면 해당 값이 아무것도 설정되지 않을 수 있지만 요소는 여전히 배열에 있습니다.
phil294

29

원하지 않는 요소없이 새 배열을 만든 다음 이전 배열에 다시 할당 할 수 있습니다. 이것은 다음에서 작동합니다 bash.

array=(pluto pippo)
new_array=()
for value in "${array[@]}"
do
    [[ $value != pluto ]] && new_array+=($value)
done
array=("${new_array[@]}")
unset new_array

결과 :

echo "${array[@]}"
pippo

14

이것이 위치를 안다면 값을 설정 해제하는 가장 직접적인 방법입니다.

$ array=(one two three)
$ echo ${#array[@]}
3
$ unset 'array[1]'
$ echo ${array[@]}
one three
$ echo ${#array[@]}
2

3
시도 echo ${array[1]}하면 null 문자열이 표시됩니다. 그리고 three당신 이 할 필요가 있습니다 echo ${array[2]}. 따라서 unsetbash 배열에서 요소를 제거하는 올바른 메커니즘이 아닙니다.
rashok apr.

@rashok, no ${array[1]+x}는 null 문자열이므로 array[1]설정되지 않습니다. unset나머지 요소의 색인을 변경하지 않습니다. unset에 대한 인수를 인용 할 필요가 없습니다. 배열 요소를 파괴하는 방법은 Bash 매뉴얼에 설명되어 있습니다 .
jarno

@rashok 왜 안되는지 모르겠어요. ${array[1]}크기가 2 라고해서 존재 한다고 가정 할 수는 없습니다 ${!array[@]}. 인덱스를 원하면를 확인하십시오 .
Daniel C. Sobral

4

다음은 mapfile을 사용한 한 줄 솔루션입니다.

$ mapfile -d $'\0' -t arr < <(printf '%s\0' "${arr[@]}" | grep -Pzv "<regexp>")

예:

$ arr=("Adam" "Bob" "Claire"$'\n'"Smith" "David" "Eve" "Fred")

$ echo "Size: ${#arr[*]} Contents: ${arr[*]}"

Size: 6 Contents: Adam Bob Claire
Smith David Eve Fred

$ mapfile -d $'\0' -t arr < <(printf '%s\0' "${arr[@]}" | grep -Pzv "^Claire\nSmith$")

$ echo "Size: ${#arr[*]} Contents: ${arr[*]}"

Size: 5 Contents: Adam Bob David Eve Fred

이 방법은 grep 명령을 수정 / 교환하여 큰 유연성을 허용하며 배열에 빈 문자열을 남기지 않습니다.


1
printf '%s\n' "${array[@]}"그 못생긴 IFS/ echo물건 대신 사용하십시오 .
gniourf_gniourf

줄 바꿈이 포함 된 필드에서는 실패합니다.
gniourf_gniourf

@Socowi 적어도 bash 4.4.19에서는 틀 렸습니다. 인수 없이는 -d $'\0'완벽하게 작동 -d하지 않습니다.
Niklas Holm

아 네, 섞었습니다. 죄송합니다. 내가 의미하는 바는 : -d $'\0'동일 -d $'\0 something'하거나 그냥 -d ''.
Socowi

사용 다치게하지 않습니다 $'\0'명확하지만위한
니클라스 홀름

4

이 대답은 성능이 중요한 대형 배열에서 여러 값을 삭제하는 경우에만 해당됩니다.

가장 많이 투표 한 솔루션은 (1) 배열의 패턴 대체 또는 (2) 배열 요소에 대한 반복입니다. 첫 번째는 빠르지 만 고유 한 접두사가있는 요소 만 처리 할 수 ​​있고, 두 번째는 O (n * k), n = 배열 ​​크기, k = 제거 할 요소가 있습니다. 연관 배열은 상대적으로 새로운 기능이며 질문이 처음 게시되었을 때 일반적이지 않았을 수 있습니다.

정확한 일치 케이스의 경우 큰 n과 k를 사용하면 O (n k)에서 O (n + k log (k))로 성능을 향상시킬 수 있습니다 . 실제로 O (n)는 k가 n보다 훨씬 낮다고 가정합니다. 대부분의 속도 향상은 제거 할 항목을 식별하기 위해 연관 배열을 사용하는 것입니다.

성능 (n-array 크기, 삭제할 k- 값). 사용자 시간의 성능 측정 초

   N     K     New(seconds) Current(seconds)  Speedup
 1000   10     0.005        0.033             6X
10000   10     0.070        0.348             5X
10000   20     0.070        0.656             9X
10000    1     0.043        0.050             -7%

예상대로 current해는 N * K에 선형이고, fast해는 훨씬 더 낮은 상수를 사용하여 사실상 K에 선형입니다. fast용액은 약간 느린 VS이다 current용액 때 추가 설정 때문에 K = 1.

'빠른'솔루션 : 배열 = 입력 목록, 삭제 = 제거 할 값 목록.

        declare -A delk
        for del in "${delete[@]}" ; do delk[$del]=1 ; done
                # Tag items to remove, based on
        for k in "${!array[@]}" ; do
                [ "${delk[${array[$k]}]-}" ] && unset 'array[k]'
        done
                # Compaction
        array=("${array[@]}")

current가장 많이 득표 한 답변에서 솔루션과 비교하여 벤치마킹 했습니다.

    for target in "${delete[@]}"; do
        for i in "${!array[@]}"; do
            if [[ ${array[i]} = $target ]]; then
                unset 'array[i]'
            fi
        done
    done
    array=("${array[@]}")

3

다음은 bash 변수 간접 지정과 관련된 (아마도 매우 bash 특정) 작은 함수입니다 unset. 텍스트 대체 또는 빈 요소 폐기를 포함하지 않고 인용 / 공백 등에 문제가없는 일반적인 솔루션입니다.

delete_ary_elmt() {
  local word=$1      # the element to search for & delete
  local aryref="$2[@]" # a necessary step since '${!$2[@]}' is a syntax error
  local arycopy=("${!aryref}") # create a copy of the input array
  local status=1
  for (( i = ${#arycopy[@]} - 1; i >= 0; i-- )); do # iterate over indices backwards
    elmt=${arycopy[$i]}
    [[ $elmt == $word ]] && unset "$2[$i]" && status=0 # unset matching elmts in orig. ary
  done
  return $status # return 0 if something was deleted; 1 if not
}

array=(a 0 0 b 0 0 0 c 0 d e 0 0 0)
delete_ary_elmt 0 array
for e in "${array[@]}"; do
  echo "$e"
done

# prints "a" "b" "c" "d" in lines

시길 delete_ary_elmt ELEMENT ARRAYNAME없이 사용하세요 $. 접두사 일치 == $word== $word*위해 for 를 전환하십시오 . 사용 ${elmt,,} == ${word,,}대소 문자를 구분하지 일치하는; 등, bash가 [[지원하는 모든 것.

입력 배열의 인덱스를 결정하고 역순으로 반복하여 작동합니다 (따라서 요소를 삭제해도 반복 순서가 망가지지 않습니다). 인덱스를 얻으려면 bash 변수 indirection을 통해 수행 할 수있는 이름으로 입력 배열에 액세스해야합니다 x=1; varname=x; echo ${!varname} # prints "1".

와 같은 이름으로 배열에 액세스 할 수 없습니다 aryname=a; echo "${$aryname[@]}.이 경우 오류가 발생합니다. 할 수 없습니다 aryname=a; echo "${!aryname[@]}". 이것은 변수의 인덱스를 제공합니다 aryname(배열은 아니지만). 작동하는 것은 aryref="a[@]"; echo "${!aryref}"배열의 요소를 인쇄하여 a쉘 단어 인용 및 공백을 정확히 echo "${a[@]}". 그러나 이것은 길이나 인덱스를 인쇄하는 것이 아니라 배열의 요소를 인쇄 할 때만 작동합니다 ( aryref="!a[@]"또는 aryref="#a[@]"또는 "${!!aryref}"또는 "${#!aryref}"모두 실패).

그래서 bash 간접 지정을 통해 원래 배열을 이름으로 복사하고 복사본에서 색인을 얻습니다. 인덱스를 반대로 반복하기 위해 C 스타일 for 루프를 사용합니다. 또한를 통해 인덱스에 액세스하고을 사용하여 ${!arycopy[@]}반전하여 수행 할 수 있습니다 . 이는 입력 라인 순서를 뒤집는 taca cat입니다.

변수 간접이없는 함수 솔루션은 아마도를 포함해야 할 것입니다 eval. 이는 해당 상황에서 사용하기에 안전 할 수도 있고 안전하지 않을 수도 있습니다 (알 수 없습니다).


이것은 거의 잘 작동하지만 함수에 전달 된 초기 배열을 다시 선언하지 않으므로 초기 배열에 값이 누락되어 있지만 인덱스도 엉망이됩니다. 이것이 의미하는 바는 동일한 어레이에서 delete_ary_elmt에 대한 다음 호출이 작동하지 않거나 잘못된 것을 제거한다는 것입니다. 예를 들어, 붙여 넣은 후 delete_ary_elmt "d" array어레이를 실행 한 다음 다시 인쇄 해보십시오 . 잘못된 요소가 제거되는 것을 볼 수 있습니다. 마지막 요소를 제거해도 작동하지 않습니다.
Scott은

2

위의 답변을 확장하기 위해 다음을 사용하여 부분 일치없이 배열에서 여러 요소를 제거 할 수 있습니다.

ARRAY=(one two onetwo three four threefour "one six")
TO_REMOVE=(one four)

TEMP_ARRAY=()
for pkg in "${ARRAY[@]}"; do
    for remove in "${TO_REMOVE[@]}"; do
        KEEP=true
        if [[ ${pkg} == ${remove} ]]; then
            KEEP=false
            break
        fi
    done
    if ${KEEP}; then
        TEMP_ARRAY+=(${pkg})
    fi
done
ARRAY=("${TEMP_ARRAY[@]}")
unset TEMP_ARRAY

그러면 다음을 포함하는 배열이 생성됩니다. (two onetwo three threefour "one six")



1

부분 답변 만

배열의 첫 번째 항목을 삭제하려면

unset 'array[0]'

배열의 마지막 항목을 삭제하려면

unset 'array[-1]'

@gniourf_gniourf의 인수에 따옴표를 사용할 필요가 없습니다 unset.
jarno

2
@jarno :이 따옴표를 사용해야합니다. array0현재 디렉토리에 이름이 지정된 파일이있는 경우 array[0]glob이므로 먼저 array0unset 명령 이전 으로 확장됩니다 .
gniourf_gniourf

@gniourf_gniourf 맞습니다. 이것은 현재 "unset name [subscript]가 index subscript에서 배열 요소를 파괴한다"라고 말하는 Bash Reference Manual 에서 수정되어야합니다 .
jarno

1

사용 unset

특정 인덱스에서 요소를 제거하기 위해 사용 unset하고 다른 배열로 복사 할 수 있습니다 . unset이 경우 에만 필요하지 않습니다. unset요소를 제거하지 않기 때문에 배열의 특정 인덱스에 null 문자열을 설정합니다.

declare -a arr=('aa' 'bb' 'cc' 'dd' 'ee')
unset 'arr[1]'
declare -a arr2=()
i=0
for element in "${arr[@]}"
do
    arr2[$i]=$element
    ((++i))
done
echo "${arr[@]}"
echo "1st val is ${arr[1]}, 2nd val is ${arr[2]}"
echo "${arr2[@]}"
echo "1st val is ${arr2[1]}, 2nd val is ${arr2[2]}"

출력은

aa cc dd ee
1st val is , 2nd val is cc
aa cc dd ee
1st val is cc, 2nd val is dd

사용 :<idx>

:<idx>also를 사용하여 일부 요소 세트를 제거 할 수 있습니다. 예를 들어 첫 번째 요소를 제거하려면 :1아래와 같이 사용할 수 있습니다 .

declare -a arr=('aa' 'bb' 'cc' 'dd' 'ee')
arr2=("${arr[@]:1}")
echo "${arr2[@]}"
echo "1st val is ${arr2[1]}, 2nd val is ${arr2[2]}"

출력은

bb cc dd ee
1st val is cc, 2nd val is dd

0

POSIX 쉘 스크립트에는 배열이 없습니다.

따라서 bash, korn shells 또는 zsh.

따라서 현재 귀하의 질문에 답할 수 없습니다.

아마도 이것이 당신을 위해 일할 것입니다.

unset array[$delete]

2
안녕하세요, 저는 bash shell atm을 사용하고 있습니다. 그리고 "$ delete"는 요소의 위치가 아니라 문자열 자체입니다. 나는 생각하지 않는다 그래서 "해제"작동합니다
알렉스

0

실제로 쉘 구문에는 항목이 제거되어야 할 때 배열을 쉽게 재구성 할 수있는 동작이 내장되어 있음을 알았습니다.

# let's set up an array of items to consume:
x=()
for (( i=0; i<10; i++ )); do
    x+=("$i")
done

# here, we consume that array:
while (( ${#x[@]} )); do
    i=$(( $RANDOM % ${#x[@]} ))
    echo "${x[i]} / ${x[@]}"
    x=("${x[@]:0:i}" "${x[@]:i+1}")
done

bash의 x+=()구문을 사용하여 배열을 어떻게 구성했는지 주목 하세요?

실제로 한 번에 전체 다른 배열의 내용을 사용하여 둘 이상의 항목을 추가 할 수 있습니다.


0

http://wiki.bash-hackers.org/syntax/pe#substring_removal

$ {PARAMETER # PATTERN} # 처음부터 제거

$ {PARAMETER ## PATTERN} # 처음부터 제거, 탐욕스러운 일치

$ {PARAMETER % PATTERN} # 끝에서 제거

$ {PARAMETER %% PATTERN} # 욕심 많은 경기 끝에서 제거

전체 제거 요소를 수행하려면 if 문으로 unset 명령을 수행해야합니다. 다른 변수에서 접두사를 제거하거나 배열에서 공백을 지원하는 데 신경 쓰지 않는다면 따옴표를 삭제하고 for 루프는 잊어 버릴 수 있습니다.

어레이를 정리하는 몇 가지 다른 방법은 아래 예를 참조하십시오.

options=("foo" "bar" "foo" "foobar" "foo bar" "bars" "bar")

# remove bar from the start of each element
options=("${options[@]/#"bar"}")
# options=("foo" "" "foo" "foobar" "foo bar" "s" "")

# remove the complete string "foo" in a for loop
count=${#options[@]}
for ((i = 0; i < count; i++)); do
   if [ "${options[i]}" = "foo" ] ; then
      unset 'options[i]'
   fi
done
# options=(  ""   "foobar" "foo bar" "s" "")

# remove empty options
# note the count variable can't be recalculated easily on a sparse array
for ((i = 0; i < count; i++)); do
   # echo "Element $i: '${options[i]}'"
   if [ -z "${options[i]}" ] ; then
      unset 'options[i]'
   fi
done
# options=("foobar" "foo bar" "s")

# list them with select
echo "Choose an option:"
PS3='Option? '
select i in "${options[@]}" Quit
 do
    case $i in 
       Quit) break ;;
       *) echo "You selected \"$i\"" ;;
    esac
 done

산출

Choose an option:
1) foobar
2) foo bar
3) s
4) Quit
Option? 

도움이되기를 바랍니다.


0

ZSH에서 이것은 매우 쉽습니다 (이해하기 쉽도록 가능한 한 필요한 것보다 더 많은 bash 호환 구문을 사용합니다).

# I always include an edge case to make sure each element
# is not being word split.
start=(one two three 'four 4' five)
work=(${(@)start})

idx=2
val=${work[idx]}

# How to remove a single element easily.
# Also works for associative arrays (at least in zsh)
work[$idx]=()

echo "Array size went down by one: "
[[ $#work -eq $(($#start - 1)) ]] && echo "OK"

echo "Array item "$val" is now gone: "
[[ -z ${work[(r)$val]} ]] && echo OK

echo "Array contents are as expected: "
wanted=("${start[@]:0:1}" "${start[@]:2}")
[[ "${(j.:.)wanted[@]}" == "${(j.:.)work[@]}" ]] && echo "OK"

echo "-- array contents: start --"
print -l -r -- "-- $#start elements" ${(@)start}
echo "-- array contents: work --"
print -l -r -- "-- $#work elements" "${work[@]}"

결과 :

Array size went down by one:
OK
Array item two is now gone:
OK
Array contents are as expected:
OK
-- array contents: start --
-- 5 elements
one
two
three
four 4
five
-- array contents: work --
-- 4 elements
one
three
four 4
five

죄송합니다. 방금 시도했습니다. 연관 배열을 위해 zsh에서 작동하지 않았습니다
Falk

잘 작동하고 방금 테스트했습니다. 당신을 위해 작동하지 않는 것? 작동하지 않는 부분을 최대한 자세히 설명해주세요. 어떤 ZSH 버전을 사용하고 있습니까?
trevorj

0

이 구문도 있습니다. 예를 들어 두 번째 요소를 삭제하려는 경우 :

array=("${array[@]:0:1}" "${array[@]:2}")

이것은 사실 2 개의 탭을 연결 한 것입니다. 첫 번째는 인덱스 0에서 인덱스 1 (배타적)까지, 두 번째는 인덱스 2에서 끝까지입니다.


-1

내가하는 일은 :

array="$(echo $array | tr ' ' '\n' | sed "/itemtodelete/d")"

BAM, 해당 항목이 제거됩니다.


1
이것은 array=('first item' 'second item').
Benjamin W.

-1

이것은 간단한 경우에 작동하지만 (a)에 정규식 특수 문자가 $delete있거나 (b) 항목에 공백이 전혀 있으면 중단되는 빠르고 더러운 솔루션입니다 . 로 시작:

array+=(pluto)
array+=(pippo)
delete=(pluto)

정확히 일치하는 모든 항목 삭제 $delete:

array=(`echo $array | fmt -1 | grep -v "^${delete}$" | fmt -999999`)

결과적으로 echo $array-> pippo, 배열인지 확인 : echo $array[1]-> pippo

fmt약간 모호합니다. fmt -1첫 번째 열에서 줄 바꿈합니다 (각 항목을 고유 한 줄에 배치합니다. 여기에서 공백에있는 항목으로 문제가 발생합니다.) fmt -999999다시 한 줄로 풀고 항목 사이의 공백을 되돌립니다. 이를 수행하는 다른 방법이 있습니다 xargs.

부록 : 첫 번째 일치 항목 만 삭제하려면 여기에 설명 된대로 sed를 사용 하십시오 .

array=(`echo $array | fmt -1 | sed "0,/^${delete}$/{//d;}" | fmt -999999`)

-1

다음과 같은 것은 어떻습니까?

array=(one two three)
array_t=" ${array[@]} "
delete=one
array=(${array_t// $delete / })
unset array_t

-1

사용 배열 인덱스와의 충돌을 피하기 위해 unset- 참조 https://stackoverflow.com/a/49626928/3223785https://stackoverflow.com/a/47798640/3223785를 : 자체에 배열을 재 할당 - 자세한 내용은 ARRAY_VAR=(${ARRAY_VAR[@]}).

#!/bin/bash

ARRAY_VAR=(0 1 2 3 4 5 6 7 8 9)
unset ARRAY_VAR[5]
unset ARRAY_VAR[4]
ARRAY_VAR=(${ARRAY_VAR[@]})
echo ${ARRAY_VAR[@]}
A_LENGTH=${#ARRAY_VAR[*]}
for (( i=0; i<=$(( $A_LENGTH -1 )); i++ )) ; do
    echo ""
    echo "INDEX - $i"
    echo "VALUE - ${ARRAY_VAR[$i]}"
done

exit 0

[참조 : https://tecadmin.net/working-with-array-bash-script/ ]


-2
#/bin/bash

echo "# define array with six elements"
arr=(zero one two three 'four 4' five)

echo "# unset by index: 0"
unset -v 'arr[0]'
for i in ${!arr[*]}; do echo "arr[$i]=${arr[$i]}"; done

arr_delete_by_content() { # value to delete
        for i in ${!arr[*]}; do
                [ "${arr[$i]}" = "$1" ] && unset -v 'arr[$i]'
        done
        }

echo "# unset in global variable where value: three"
arr_delete_by_content three
for i in ${!arr[*]}; do echo "arr[$i]=${arr[$i]}"; done

echo "# rearrange indices"
arr=( "${arr[@]}" )
for i in ${!arr[*]}; do echo "arr[$i]=${arr[$i]}"; done

delete_value() { # value arrayelements..., returns array decl.
        local e val=$1; new=(); shift
        for e in "${@}"; do [ "$val" != "$e" ] && new+=("$e"); done
        declare -p new|sed 's,^[^=]*=,,'
        }

echo "# new array without value: two"
declare -a arr="$(delete_value two "${arr[@]}")"
for i in ${!arr[*]}; do echo "arr[$i]=${arr[$i]}"; done

delete_values() { # arraydecl values..., returns array decl. (keeps indices)
        declare -a arr="$1"; local i v; shift
        for v in "${@}"; do 
                for i in ${!arr[*]}; do
                        [ "$v" = "${arr[$i]}" ] && unset -v 'arr[$i]'
                done
        done
        declare -p arr|sed 's,^[^=]*=,,'
        }
echo "# new array without values: one five (keep indices)"
declare -a arr="$(delete_values "$(declare -p arr|sed 's,^[^=]*=,,')" one five)"
for i in ${!arr[*]}; do echo "arr[$i]=${arr[$i]}"; done

# new array without multiple values and rearranged indices is left to the reader

1
답변에 대한 의견이나 설명을 추가 할 수 있습니까?
Michael
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.