বাশ - একটি অ্যারে বিপরীত


16

অ্যারেটি বিপরীত করার কোনও সহজ উপায় আছে কি?

#!/bin/bash

array=(1 2 3 4 5 6 7)

echo "${array[@]}"

সুতরাং আমি পেতে হবে: 7 6 5 4 3 2 1
পরিবর্তে:1 2 3 4 5 6 7

উত্তর:


15

আমি লিখিত হিসাবে প্রশ্নের উত্তর দিয়েছি, এবং এই কোড অ্যারে বিপরীত। (অ্যারেটিকে উল্টিয়ে না দিয়ে উপাদানগুলি বিপরীত ক্রমে মুদ্রণ করা forশেষ উপাদান থেকে শূন্যের নিচে গণনা করা একটি লুপ মাত্র )) এটি একটি স্ট্যান্ডার্ড "প্রথম এবং শেষ" অ্যালগরিদম is

array=(1 2 3 4 5 6 7)

min=0
max=$(( ${#array[@]} -1 ))

while [[ min -lt max ]]
do
    # Swap current first and last elements
    x="${array[$min]}"
    array[$min]="${array[$max]}"
    array[$max]="$x"

    # Move closer
    (( min++, max-- ))
done

echo "${array[@]}"

এটি বিজোড় এবং এমনকি দৈর্ঘ্যের অ্যারেগুলির জন্য কাজ করে।


দয়া করে একটি নোট করুন যে এটি স্পার্স অ্যারেগুলির জন্য কাজ করে না।
আইজাক

আপনার যদি এগুলি পরিচালনা করতে হয় তবে @ ইসাক এ স্ট্যাক ওভারফ্লোতে একটি সমাধান আছে।
রোয়াইমা

এখানে সমাধান ।
আইজাক

18

অপর একটি প্রচলিত পদ্ধতি:

#!/bin/bash

array=(1 2 3 4 5 6 7)

f() { array=("${BASH_ARGV[@]}"); }

shopt -s extdebug
f "${array[@]}"
shopt -u extdebug

echo "${array[@]}"

আউটপুট:

7 6 5 4 3 2 1

যদি extdebug সক্ষম করা BASH_ARGVথাকে তবে অ্যারে কোনও ফাংশনে বিপরীত ক্রমে সমস্ত অবস্থানগত পরামিতি ধারণ করে।


এটি একটি দুর্দান্ত কৌশল!
ভ্যালেন্টাইন বাজরামি

15

প্রচলিত পদ্ধতি (সমস্ত শুদ্ধ নয়) bash ):

  • যদি অ্যারের সমস্ত উপাদানগুলি কেবলমাত্র একটি অক্ষর হয় (প্রশ্নের মতো) আপনি ব্যবহার করতে পারেন rev:

    echo "${array[@]}" | rev
  • অন্যথায়:

    printf '%s\n' "${array[@]}" | tac | tr '\n' ' '; echo
  • এবং যদি আপনি ব্যবহার করতে পারেন zsh:

    echo ${(Oa)array}

স্রেফ সন্ধান করা হয়েছে tac, catমনে রাখা বেশ বিপরীত হিসাবে , ধন্যবাদ!
নাথ

3
যদিও আমি ধারণাটি পছন্দ করি তবে আমার revউল্লেখ করতে revহবে যে দুটি সংখ্যার সংখ্যার জন্য সঠিকভাবে কাজ করবে না। উদাহরণস্বরূপ 12 রেভ ব্যবহারের একটি অ্যারের উপাদান হিসাবে মুদ্রিত হবে 21। এটি ব্যবহার করে দেখুন ;-)
জর্জ ভ্যাসিলিও

@ জর্জিভাসিলিউ হ্যাঁ, এটি তখনই কাজ করবে যখন সমস্ত উপাদানগুলি একটি অক্ষর (সংখ্যা, অক্ষর, বিরামচিহ্ন, ...) হয়। এ কারণেই আমি দ্বিতীয়, আরও সাধারণ সমাধান দিয়েছি।
jimmij

8

আপনি যদি আসলে অন্য অ্যারেতে বিপরীতটি চান:

reverse() {
    # first argument is the array to reverse
    # second is the output array
    declare -n arr="$1" rev="$2"
    for i in "${arr[@]}"
    do
        rev=("$i" "${rev[@]}")
    done
}

তারপর:

array=(1 2 3 4)
reverse array foo
echo "${foo[@]}"

দেয়:

4 3 2 1

এটি অ্যারে সূচক অনুপস্থিত রয়েছে এমন ক্ষেত্রে সঠিকভাবে পরিচালনা করতে হবে, বলুন যে আপনার array=([1]=1 [2]=2 [4]=4)ক্ষেত্রে 0 থেকে সর্বোচ্চ সূচীতে লুপিং অতিরিক্ত, খালি, উপাদান যুক্ত করতে পারে।


এটির জন্য ধন্যবাদ, এটি বেশ ভালভাবে কাজ করে, যদিও কোনও কারণে shellcheckদুটি সতর্কতা প্রিন্ট করে: array=(1 2 3 4) <-- SC2034: array appears unused. Verify it or export it.এবং এর জন্য:echo "${foo[@]}" <-- SC2154: foo is referenced but not assigned.
নাথ

1
@ নাথ এগুলি পরোক্ষভাবে ব্যবহার করা হচ্ছে, এটাই declareলাইন।
মুরু

চতুর, তবে মনে রাখবেন যে declare -n4.3 এর আগে ব্যাশ সংস্করণগুলিতে কাজ করবে না।
জি-ম্যান 21'৩৩-এ 'মনিকাকে পুনরায় ইনস্টল করুন'

8

জায়গায় অ্যারে অবস্থানগুলি অদলবদল করতে (এমনকি বিরল অ্যারে সহ) (বাশ 3.0.০ থেকে):

#!/bin/bash
# Declare an sparse array to test:
array=([5]=101 [6]=202 [10]=303 [11]=404 [20]=505 [21]=606 [40]=707)
echo "Initial array values"
declare -p array

swaparray(){ local temp; temp="${array[$1]}"
             array[$1]="${array[$2]}"
             array[$2]="$temp"
           }

ind=("${!array[@]}")                         # non-sparse array of indexes.

min=-1; max="${#ind[@]}"                     # limits to one before real limits.
while [[ min++ -lt max-- ]]                  # move closer on each loop.
do
    swaparray "${ind[min]}" "${ind[max]}"    # Exchange first and last
done

echo "Final Array swapped in place"
declare -p array
echo "Final Array values"
echo "${array[@]}"

ফাঁসি কার্যকর:

./script
Initial array values
declare -a array=([5]="101" [6]="202" [10]="303" [11]="404" [20]="505" [21]="606" [40]="707")

Final Array swapped in place
declare -a array=([5]="707" [6]="606" [10]="505" [11]="404" [20]="303" [21]="202" [40]="101")

Final Array values
707 606 505 404 303 202 101

পুরানো বাশের জন্য, আপনাকে লুপ ব্যবহার করতে হবে (ব্যাশে (2.04)) এবং $aপিছনের স্থানটি এড়াতে ব্যবহার করতে হবে:

#!/bin/bash

array=(101 202 303 404 505 606 707)
last=${#array[@]}

a=""
for (( i=last-1 ; i>=0 ; i-- ));do
    printf '%s%s' "$a" "${array[i]}"
    a=" "
done
echo

২.০৩ সাল থেকে ব্যাশের জন্য:

#!/bin/bash
array=(101 202 303 404 505 606 707)
last=${#array[@]}

a="";i=0
while [[ last -ge $((i+=1)) ]]; do 
    printf '%s%s' "$a" "${array[ last-i ]}"
    a=" "
done
echo

এছাড়াও (বিটওয়াইস নেগেশন অপারেটর ব্যবহার করে) (যেহেতু ব্যাশ ৪.২++):

#!/bin/bash
array=(101 202 303 404 505 606 707)
last=${#array[@]}

a=""
for (( i=0 ; i<last ; i++ )); do 
    printf '%s%s' "$a" "${array[~i]}"
    a=" "
done
echo

নেতিবাচক সাবস্ক্রিপ্ট সহ শেষ থেকে একটি অ্যারের উপাদানগুলি সম্বোধন করা 4.3 এর আগে ব্যাশ সংস্করণগুলিতে কাজ করবে না বলে মনে হচ্ছে।
জি-ম্যান 21 'এ 21

1
প্রকৃতপক্ষে, নেতিবাচক সংখ্যাগুলিকে সম্বোধন করা 4.2-আলফাতে পরিবর্তন করা হয়েছিল। এবং অবহেলিত মান সহ স্ক্রিপ্ট সেই সংস্করণ থেকে কাজ করে। @ জি-ম্যান পি। সূচকযুক্ত অ্যারেতে নেতিবাচক সাবস্ক্রিপ্টগুলি এখন সর্বাধিক নির্ধারিত সূচক + ১ থেকে অফসেট হিসাবে বিবেচিত হয় তবে বাশ-হ্যাকাররা রিপোর্ট করেছেন ভুলভাবে ৪.১ সংখ্যাযুক্ত সূচিকৃত অ্যারেগুলি নেতিবাচক সূচকগুলি ব্যবহার করে শেষ থেকে অ্যাক্সেস করা যেতে পারে
আইজাক

3

কুরুচিপূর্ণ, অবিস্মরণীয়, তবে ওয়ান-লাইনার:

eval eval echo "'\"\${array['{$((${#array[@]}-1))..0}']}\"'"

না সহজ, কিন্তু ছোট: eval eval echo "'\"\${array[-'{1..${#array[@]}}']}\"'"
ইসহাক

এমনকি স্পার্স অ্যারেগুলির জন্যও:ind=("${!array[@]}");eval eval echo "'\"\${array[ind[-'{1..${#array[@]}}']]}\"'"
আইজাক

@ আইসাক কিন্তু দুর্ভাগ্যক্রমে, আর এক-লাইনার এবং বিরল অ্যারে সংস্করণের জন্য কেবল কুরুচিপূর্ণ এবং অকল্পনীয়। (তবুও ছোট অ্যারেগুলির পাইপের তুলনায় দ্রুত হওয়া উচিত))
ব্যবহারকারী ২৩০১৩

ভাল, প্রযুক্তিগতভাবে, এটি একটি "ওয়ান-লাইনার"; একটি আদেশ নয়, হ্যাঁ, তবে এটি একটি "ওয়ান লাইনার"। আমি রাজি, হ্যাঁ, খুব কুরুচিপূর্ণ এবং রক্ষণাবেক্ষণের সমস্যা তবে খেলতে মজা।
ইসহাক

1

যদিও আমি নতুন কিছু বলতে যাচ্ছি না এবং আমি tacঅ্যারেটি বিপরীত করতেও ব্যবহার করব , যদিও আমি বশ সংস্করণ ৪.৪ ব্যবহার করে বেলো সিঙ্গেল লাইন সমাধান উল্লেখ করার জন্য উদ্বেগজনক হবে:

$ read -d'\n' -a array < <(printf '%s\n' "${array[@]}" |tac)

পরীক্ষামূলক:

$ array=(1 2 3 4 5 6 10 11 12)
$ echo "${array[@]}"
1 2 3 4 5 6 10 11 12
$ read -d'\n' -a array < <(printf '%s\n' "${array[@]}"|tac)
$ echo "${array[@]}"
12 11 10 6 5 4 3 2 1

মনে রাখবেন যে পড়ার অভ্যন্তরে বর্ণের নামটি মূল অ্যারে হিসাবে নাম, তাই অস্থায়ী সঞ্চয়ের জন্য কোনও সাহায্যকারী অ্যারের প্রয়োজন হয় না।

আইএফএস সামঞ্জস্য করে বিকল্প বাস্তবায়ন:

$ IFS=$'\n' read -d '' -a array < <(printf '%s\n' "${array[@]}"|tac);declare -p array
declare -a array=([0]="12" [1]="11" [2]="10" [3]="6" [4]="5" [5]="4" [6]="3" [7]="2" [8]="1")

PS: আমি মনে করি উপরের সমাধানগুলি বিভিন্ন ব্যাশ বিল্টিন ফাংশন বাস্তবায়নের কারণে bashবেলো সংস্করণে কাজ করবে না ।4.4read


IFSসংস্করণ কাজ করে কিন্তু এটি মুদ্রণ হয়: declare -a array=([0]="1" [1]="2" [2]="3" [3]="4" [4]="5" [5]="6" [6]="10" [7]="11" [8]="12")। ব্যাশ ব্যবহার করা 4.4-5। আপনি সরাতে পেয়েছিলাম ;declare -p arrayপ্রথম লাইন শেষে, তারপর এটি কাজ করে ...
নাথ

1
@ নাশটি declare -pআসল অ্যারে (সূচি এবং বিষয়বস্তু) প্রিন্ট করার কেবলমাত্র দ্রুত উপায়। declare -pআপনার আসল স্ক্রিপ্টে আপনার এই আদেশের দরকার নেই । যদি আপনার অ্যারে কার্যক্রমে কিছু ভুল হয়ে যায় তবে আপনি ${array[0]}="1 2 3 4 5 6 10 11 12"একই ক্ষেত্রে শেষ করতে পারেন যে = একই সূচীতে সঞ্চিত সমস্ত মান - প্রতিধ্বনি ব্যবহার করে আপনি কোনও পার্থক্য দেখতে পাবেন না। দ্রুত অ্যারের প্রিন্টআউট ব্যবহার করে declare -p arrayআপনাকে প্রতিটি সূচীতে প্রকৃত অ্যারে অভ্যাস এবং সংশ্লিষ্ট মানটি ফিরিয়ে দেবে।
জর্জ ভ্যাসিলিউ

@ নাথ, উপায় read -d'\n'কি আপনার পক্ষে কার্যকর হয়নি?
জর্জ ভ্যাসিলিও

read -d'\n'ঠিকভাবে কাজ করে.
নথ

আহ্ তোমাকে পেয়েছি! দুঃখিত :-)
নাথ

1

একটি স্বেচ্ছাসেবী অ্যারে বিপরীত করতে (যে কোনও মান সহ কয়েকটি সংখ্যক উপাদান থাকতে পারে):

সাথে zsh:

array_reversed=("${(@Oa)array}")

সঙ্গে bash4.4+ দেওয়া যে bashভেরিয়েবল থাকতে পারে না NUL যাহাই হউক না কেন বাইট, আপনি গনুহ ব্যবহার করতে পারেন tac -s ''মুদ্রিত যেমন NUL রেকর্ড সীমায়িত উপাদানে:

readarray -td '' array_reversed < <(
  ((${#array[@]})) && printf '%s\0' "${array[@]}" | tac -s '')

POSIXly, POSIX শেল অ্যারের বিপরীতে ( $@, তৈরি $1, $2...):

code='set --'
n=$#
while [ "$n" -gt 0 ]; do
  code="$code \"\${$n}\""
  n=$((n - 1))
done
eval "$code"

1

খাঁটি বাশ সমাধান, ওয়ান-লাইনার হিসাবে কাজ করবে।

$: for (( i=${#array[@]}-1; i>=0; i-- ))
>  do rev[${#rev[@]}]=${array[i]}
>  done
$: echo  "${rev[@]}"
7 6 5 4 3 2 1

সুন্দর!!! ধন্যবাদ; এখানে অনুলিপি করার জন্য একটি লাইনার :-); অ্যারে = (1 2 3 4 5 6 7); (i = $ {# অ্যারে [@]} - 1; i> = 0; i--)) এর জন্য করুন; রেভ [$ {# রেভ [@]}] = $ ray অ্যারে [i]}; সম্পন্ন; প্রতিধ্বনি "$ {রেভ [@]}" `
নাথ

করা rev+=( "${array[i]}" )সহজ মনে হচ্ছে ।
ইসহাক

একজনের ছয়, অন্যটির অর্ধ-ডজন। আমি সেই সিনট্যাক্সটির পিছনে নেই, তবে এর কোনও কারণ নেই - কেবল কুসংস্কার এবং পছন্দ। তুমি করো
পল হজস

-1

আপনি ব্যবহার বিবেচনা করতে পারেন seq

array=(1 2 3 4 5 6 7)

for i in $(seq $((${#array[@]} - 1)) -1 0); do
    echo ${array[$i]}
done

ফ্রিবিএসডি-তে আপনি -1 ইনক্রিমেন্ট প্যারামিটার বাদ দিতে পারেন:

for i in $(seq $((${#array[@]} - 1)) 0); do
    echo ${array[$i]}
done

নোট করুন যে এটি অ্যারেটিকে বিপরীত করে না, এটি কেবল বিপরীত ক্রমে প্রিন্ট করে।
রোয়াইমা

সম্মত হোন, আমার বক্তব্যটি সূচকগুলি অ্যাক্সেসকে বিকল্প হিসাবে বিবেচনা করাও ছিল ..
এম

-2

সজোরে আঘাত

array=(1 2 3 4 5 6 7)
echo "${array[@]} " | tac -s ' '

অথবা

array=(1 2 3 4 5 6 7)
reverse=$(echo "${array[@]} " | tac -s ' ')
echo ${reverse[@]}

ফলাফল

7 6 5 4 3 2 1

সংস্করণ

$ tac --version
tac (GNU coreutils) 8.28

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.