উপাদান দৈর্ঘ্য অনুসারে বাছাই অ্যারে?


9

স্ট্রিংগুলির একটি অ্যারে দেওয়া, আমি প্রতিটি উপাদানের দৈর্ঘ্য অনুসারে অ্যারেটিকে সাজিয়ে তুলতে চাই।

উদাহরণ স্বরূপ...

    array=(
    "tiny string"
    "the longest string in the list"
    "middle string"
    "medium string"
    "also a medium string"
    "short string"
    )

বাছাই করা উচিত ...

    "the longest string in the list"
    "also a medium string"
    "medium string"
    "middle string"
    "short string"
    "tiny string"

(বোনাস হিসাবে, তালিকাটি বর্ণানুক্রমিকভাবে একই দৈর্ঘ্যের স্ট্রিং বাছাই করলে ভাল লাগবে the উপরের উদাহরণে তারা একই দৈর্ঘ্য হওয়া সত্ত্বেও medium stringবাছাই করা হয়েছিল middle stringBut তবে এটি "কঠোর" প্রয়োজনীয়তা নয়, যদি এটি অতিরিক্ত জটিল করে তোলে সমাধান)।

অ্যারেটি স্থানে বাছাই করা থাকলে (যেমন "অ্যারে" সংশোধন করা হয়) বা একটি নতুন সাজানো অ্যারে তৈরি করা হয় তা ঠিক।


1
এখানে উপর কিছু মজার উত্তর, আপনি পাশাপাশি স্ট্রিং দৈর্ঘ্য জন্য পরীক্ষার এক খাপ খাওয়ানো করতে সক্ষম হওয়া উচিত stackoverflow.com/a/30576368/2876682
frostschutz

উত্তর:


12

যদি স্ট্রিংগুলিতে নিউলাইনগুলি না থাকে তবে নিম্নলিখিতগুলির কাজ করা উচিত। এটি স্ট্রিংগুলিকে গৌণ বাছাইয়ের মানদণ্ড হিসাবে ব্যবহার করে দৈর্ঘ্য অনুসারে অ্যারের সূচকগুলি সাজায়।

#!/bin/bash
array=(
    "tiny string"
    "the longest string in the list"
    "middle string"
    "medium string"
    "also a medium string"
    "short string"
)
expected=(
    "the longest string in the list"
    "also a medium string"
    "medium string"
    "middle string"
    "short string"
    "tiny string"
)

indexes=( $(
    for i in "${!array[@]}" ; do
        printf '%s %s %s\n' $i "${#array[i]}" "${array[i]}"
    done | sort -nrk2,2 -rk3 | cut -f1 -d' '
))

for i in "${indexes[@]}" ; do
    sorted+=("${array[i]}")
done

diff <(echo "${expected[@]}") \
     <(echo "${sorted[@]}")

নোট করুন যে একটি বাস্তব প্রোগ্রামিং ভাষায় সঞ্চার করা সমাধানকে ব্যাপকভাবে সরল করতে পারে, যেমন পার্লে, আপনি ঠিক পারেন

sort { length $b <=> length $a or $a cmp $b } @array

1
পাইথনে:sorted(array, key=lambda s: (len(s), s))
wjandrea

1
রুবিতে:array.sort { |a| a.size }
দিমিত্রি কুদরিয়াভসেভ

9
readarray -t array < <(
for str in "${array[@]}"; do
    printf '%d\t%s\n' "${#str}" "$str"
done | sort -k 1,1nr -k 2 | cut -f 2- )

এটি একটি প্রক্রিয়া প্রতিস্থাপন থেকে বাছাই করা অ্যারের মানগুলি পড়ে।

প্রক্রিয়া প্রতিস্থাপন একটি লুপ থাকে। অ্যারের প্রতিটি উপাদান লুপ আউটপুট উপাদানগুলির দৈর্ঘ্য এবং একটি ট্যাব অক্ষর দ্বারা বিভক্ত হয়।

লুপ আউটপুট ক্ষুদ্রতম বৃহত্তম থেকে সংখ্যাসূচকভাবে অনুসারে বাছাই করা হয় (এবং বর্ণানুক্রমে যদি লেন্থ একই; ব্যবহারের -k 2rপরিবর্তে -k 2বর্ণানুসারে বিপরীত) এবং ফল যে পাঠানো হয় cutযা স্ট্রিং লেন্থ সঙ্গে কলাম মুছে ফেলা হবে।

পরীক্ষা স্ক্রিপ্ট অনুসারে একটি পরীক্ষা চালানোর পরে বাছাই করুন:

array=(
    "tiny string"
    "the longest string in the list"
    "middle string"
    "medium string"
    "also a medium string"
    "short string"
)

readarray -t array < <(
for str in "${array[@]}"; do
    printf '%d\t%s\n' "${#str}" "$str"
done | sort -k 1,1nr -k 2 | cut -f 2- )

printf '%s\n' "${array[@]}"
$ bash script.sh
the longest string in the list
also a medium string
medium string
middle string
short string
tiny string

এটি ধরে নিয়েছে যে স্ট্রিংগুলিতে নিউলাইনগুলি নেই। সাম্প্রতিককালে জিএনইউ সিস্টেমে bash, আপনি নিউলাইনের পরিবর্তে রেকর্ড বিভাজক হিসাবে নুল-চরিত্রটি ব্যবহার করে ডেটাতে এম্বেড করা নিউলাইনগুলিকে সমর্থন করতে পারেন:

readarray -d '' -t array < <(
for str in "${array[@]}"; do
    printf '%d\t%s\0' "${#str}" "$str"
done | sort -z -k 1,1nr -k 2 | cut -z -f 2- )

এখানে, ডাটা trailing সঙ্গে ছাপা হয় \0নতুন লাইন পরিবর্তে লুপ, sortএবং cutতাদের মাধ্যমে nul-সীমা নির্দেশ করা লাইন লেখা -zগনুহ অপশন এবং readarrayপরিশেষে সঙ্গে nul-সীমা নির্দেশ করা ডেটা সার্চ -d ''


3
লক্ষ্য করুন -d '\0'আসলে -d ''যেমন bashকমান্ড NUL অক্ষর পাস না পারেন, এমনকি তার builtins। তবে এটি NUL- তে সীমানা-d '' হিসাবে বোঝা যায় । মনে রাখবেন যে এর জন্য আপনার 4.4+ বাশ দরকার।
স্টাফেন চেজেলাস

@ StéphaneChazelas না, এটা নয় '\0', এটা $'\0'। এবং হ্যাঁ, এটা (প্রায় ঠিক) এর পরিবর্তন করে ''। তবে এটি অন্য পাঠকদের সাথে NUL ডিলিমিটার ব্যবহারের প্রকৃত অভিপ্রায়টি একত্রিত করার উপায় ।
ইসহাক

4

ব্যাশে বাছাই করার বিষয়ে আমি ইতিমধ্যে যা বলেছি তা সম্পূর্ণরূপে পুনর্বার করব না , কেবল আপনি ব্যাশের মধ্যে বাছাই করতে পারেন, তবে সম্ভবত আপনার তা করা উচিত নয়। নীচে একটি সন্নিবেশ বাছাইয়ের কেবলমাত্র ব্যাশ বাস্তবায়ন দেওয়া হচ্ছে যা ও (এন 2 ), এবং তাই কেবলমাত্র ছোট অ্যারেগুলির জন্য এটি সহনীয়। এটি হ্রাস ক্রমে তাদের দৈর্ঘ্য অনুসারে অ্যারে উপাদানগুলিকে একত্রে সাজিয়ে তোলে। এটি গৌণ বর্ণানুক্রমিক বাছাই করে না।

array=(
    "tiny string"
    "the longest string in the list"
    "middle string"
    "medium string"
    "also a medium string"
    "short string"
    )

function sort_inplace {
  local i j tmp
  for ((i=0; i <= ${#array[@]} - 2; i++))
  do
    for ((j=i + 1; j <= ${#array[@]} - 1; j++))
    do
      local ivalue jvalue
        ivalue=${#array[i]}
        jvalue=${#array[j]}
        if [[ $ivalue < $jvalue ]]
        then
                tmp=${array[i]}
                array[i]=${array[j]}
                array[j]=$tmp
        fi
    done
  done
}

echo Initial:
declare -p array

sort_inplace

echo Sorted:
declare -p array

এটি একটি বিশেষজ্ঞ সমাধান হিসাবে প্রমাণ হিসাবে, বিভিন্ন আকারের অ্যারেগুলিতে বিদ্যমান তিনটি উত্তরের সময় বিবেচনা করুন:

# 6 elements
Choroba: 0m0.004s
Kusalananda: 0m0.004s
Jeff: 0m0.018s         ## already 4 times slower!

# 1000 elements
Choroba: 0m0.004s
Kusalananda: 0m0.004s
Jeff: 0m0.021s        ## up to 5 times slower, now!

5000 elements
Choroba: 0m0.004s
Kusalananda: 0m0.004s
Jeff: 0m0.019s

# 10000 elements
Choroba: 0m0.004s
Kusalananda: 0m0.006s
Jeff: 0m0.020s

# 99000 elements
Choroba: 0m0.015s
Kusalananda: 0m0.012s
Jeff: 0m0.119s

চোরোবা এবং কুসালানান্দার সঠিক ধারণা রয়েছে: একবার দৈর্ঘ্য গণনা করুন এবং বাছাই এবং পাঠ্য প্রক্রিয়াজাতকরণের জন্য উত্সর্গীকৃত ইউটিলিটিগুলি ব্যবহার করুন।


4

হ্যাকিশ? (জটিল) এবং দৈর্ঘ্য অনুসারে অ্যারেটিকে সাজানোর জন্য দ্রুত এক লাইন উপায়
( নিউলাইন এবং স্পার্স অ্যারেগুলির জন্য নিরাপদ ):

#!/bin/bash
in=(
    "tiny string"
    "the longest
        string also containing
        newlines"
    "middle string"
    "medium string"
    "also a medium string"
    "short string"
    "test * string"
    "*"
    "?"
    "[abc]"
)

readarray -td $'\0' sorted < <(
                    for i in "${in[@]}"
                    do     printf '%s %s\0' "${#i}" "$i";
                    done |
                            sort -bz -k1,1rn -k2 |
                            cut -zd " " -f2-
                    )

printf '%s\n' "${sorted[@]}"

এক লাইনে:

readarray -td $'\0' sorted < <(for i in "${in[@]}";do printf '%s %s\0' "${#i}" "$i"; done | sort -bz -k1,1rn -k2 | cut -zd " " -f2-)

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

$ ./script
the longest
        string also containing
        newlines
also a medium string
medium string
middle string
test * string
short string
tiny string
[abc]
?
*

4

এটি অ্যারে উপাদানগুলিকে নতুন লাইনের সাথে পরিচালনা করে; এটি sortপ্রতিটি উপাদানটির দৈর্ঘ্য এবং সূচকটি পেরিয়ে কাজ করে। এটি bashএবং সঙ্গে কাজ করা উচিত ksh

in=(
    "tiny string"
    "the longest
        string also containing
        newlines"
    "middle string"
    "medium string"
    "also a medium string"
    "short string"
)
out=()

unset IFS
for a in $(for i in ${!in[@]}; do echo ${#in[i]}/$i; done | sort -rn); do
        out+=("${in[${a#*/}]}")
done

printf '"%s"\n' "${out[@]}"

যদি একই দৈর্ঘ্যের উপাদানগুলিও অভিধানিকভাবে বাছাই করতে হয় তবে লুপটি এভাবে পরিবর্তন করা যেতে পারে:

IFS='
'
for a in $(for i in ${!in[@]}; do printf '%s\n' "$i ${#in[i]} ${in[i]//$IFS/ }"; done | sort -k 2,2nr -k 3 | cut -d' ' -f1); do
        out+=("${in[$a]}")
done

এটি sortস্ট্রিংগুলিতেও যাবে (নতুন লাইনে স্পেসে পরিবর্তিত হয়ে) তবে তাদের সূচি দ্বারা উত্স থেকে গন্তব্য অ্যারেতে অনুলিপি করা হবে। উভয় উদাহরণে, $(...)কেবল সংখ্যাগুলি (এবং /প্রথম উদাহরণের অক্ষর) সম্বলিত লাইনগুলি দেখতে পাবে , সুতরাং এটি স্ট্রিংগুলিতে অক্ষর বা ফাঁকা স্থানগুলি দ্বারা বিভক্ত হবে না।


পুনরুত্পাদন করা যায় না। দ্বিতীয় উদাহরণে, $(...)কমান্ড প্রতিস্থাপনটি কেবল সূচিগুলি (নতুন লাইনের দ্বারা পৃথক করা সংখ্যার একটি তালিকা) দেখায়, কারণ cut -d' ' -f1বাছাইয়ের পরে। এটি একটি tee /dev/ttyএর শেষে সহজেই প্রদর্শিত হতে পারে $(...)
মোসভি

দুঃখিত, আমার খারাপ, আমি মিস cut
স্টাফেন চেজেলাস

@ আইসাক ${!in[@]}বা ${#in[i]}/$iপরিবর্তনশীল বিস্তৃতি উদ্ধৃত করার প্রয়োজন নেই কারণ এগুলিতে কেবল এমন সংখ্যা রয়েছে যা গ্লোব সম্প্রসারণের বিষয় নয় এবং স্থান, ট্যাব, নিউলাইনটিতে unset IFSপুনরায় সেট করবে IFS। আসলে, এগুলি উদ্ধৃত করা ক্ষতিকারক হবে , কারণ এটি মিথ্যা ধারণা দেয় যে এই জাতীয় উদ্ধৃতি কার্যকর এবং কার্যকর এবং দ্বিতীয় উদাহরণে IFSআউটপুট স্থাপন এবং / অথবা ফিল্টারিং sortনিরাপদভাবে সম্পন্ন করা যেতে পারে।
মশবির

@ আইসাক এটি ধারণ করে এবং লুপের আগে সেট করা থাকলে তা ভাঙবে নাin"testing * here"shopt -s nullglob
মশবির

3

যদি স্যুইচ করা zshকোনও বিকল্প হয় তবে সেখানে একটি হ্যাকিশ উপায় (বাইটগুলির কোনও ক্রমযুক্ত অ্যারেগুলির জন্য):

array=('' blah $'x\ny\nz' $'x\0y' '1 2 3')
sorted_array=( /(e'{reply=("$array[@]")}'nOe'{REPLY=$#REPLY}') )

zshগ্লোব কোয়ালিফায়ারগুলির মাধ্যমে এর গ্লোব বিস্তারের জন্য সাজানোর অর্ডারগুলি সংজ্ঞায়িত করার অনুমতি দেয়। সুতরাং এখানে, আমরা এটি গ্লোববিং করে স্বেচ্ছাসেবী অ্যারেগুলির জন্য এটি করার জন্য ট্র্যাকিং করছি /, তবে /অ্যারের উপাদানগুলির সাথে প্রতিস্থাপন ( e'{reply=("$array[@]")}') এবং তারপরে numerically rder o(বড় হাতের বিপরীতে O) তাদের দৈর্ঘ্যের উপর ভিত্তি করে ( Oe'{REPLY=$#REPLY}') elements

নোট করুন যে এটি অক্ষরের সংখ্যা দৈর্ঘ্যের উপর ভিত্তি করে। বাইটের সংখ্যার জন্য, লোকেলটি C( LC_ALL=C) এ সেট করুন ।

অন্য bash4.4+ পদ্ধতির (খুব বড় অ্যারে ধরে নিলে):

readarray -td '' sorted_array < <(
  perl -l0 -e 'print for sort {length $b <=> length $a} @ARGV
              ' -- "${array[@]}")

(এটি দৈর্ঘ্য বাইটে )।

এর পুরানো সংস্করণ সহ bash, আপনি সর্বদা এটি করতে পারেন:

eval "sorted_array=($(
    perl -l0 -e 'for (sort {length $b <=> length $a} @ARGV) {
      '"s/'/'\\\\''/g"'; printf " '\'%s\''", $_}' -- "${array[@]}"
  ))"

(এটিও সঙ্গে কাজ করবে ksh93, zsh, yash, mksh)।

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