আমি কীভাবে দু'জন ভেক্টরকে একইভাবে দু'টি ভেক্টর ব্যবহার করে এমন মানদণ্ডের সাথে বাছাই করতে পারি?


85

আমি কীভাবে দু'জন ভেক্টরকে একইভাবে দু'টি ভেক্টর ব্যবহার করে এমন মানদণ্ডের সাথে বাছাই করতে পারি?

উদাহরণস্বরূপ, ধরুন আমার কাছে একই আকারের দুটি ভেক্টর রয়েছে:

vector<MyObject> vectorA;
vector<int> vectorB;

আমি তারপর vectorAকিছু তুলনা ফাংশন ব্যবহার করে বাছাই । এই বাছাই পুনরায় সাজানো vectorA। আমি কীভাবে একই পুনঃক্রম প্রয়োগ করতে vectorBপারি?


একটি বিকল্প একটি কাঠামো তৈরি করা হয়:

struct ExampleStruct {
    MyObject mo;
    int i;
};

এবং তারপরে এমন কোনও ভেক্টরকে বাছাই করুন যাতে সামগ্রীগুলি থাকে vectorAএবং vectorBএকক ভেক্টরটিতে জিপ করা থাকে:

// vectorC[i] is vectorA[i] and vectorB[i] combined
vector<ExampleStruct> vectorC;

এটি কোনও আদর্শ সমাধানের মতো বলে মনে হচ্ছে না। বিশেষত সি ++ 11 এ কি অন্যান্য বিকল্প রয়েছে?


আপনি সম্ভবত কিছু ইনপুট এবং সংশ্লিষ্ট কাঙ্ক্ষিত আউটপুট সহ একটি উদাহরণ সরবরাহ করতে পারেন? প্রশ্নটি বুঝতে আমার সমস্যা হচ্ছে
অ্যান্ডি প্রোল

আমি মনে করি তিনি (কার্যকরভাবে) সামগ্রীর vectorAএবং vectorBউভয় সামগ্রীর বিষয়বস্তু অনুসারে বাছাই করতে চান vectorB
মাকিং হাঁস

আমি মনে করি এই প্রশ্নটি যদি হুবহু সদৃশ না হয় তবে এটি একটি নিকট সদৃশ
Mooing Duck

তৃতীয় ভেক্টর বাছাই করার বিষয়ে (সূচকগুলির 0, ... ভেক্টরএ.সাইজ ()), ভেক্টরএর মানগুলির উপর ভিত্তি করে এবং ভেক্টরবিতে এই সূচকগুলি "প্রয়োগ" করুন? যেমন স্ট্যাকওভারফ্লো
আন্দ্রে

ব্যক্তিগতভাবে, আমি বরং একটি চাই vector<pair<MyObject, int>>। তারপরে দুটি তালিকা সিঙ্কের বাইরে চলে যাওয়ার বিষয়ে আপনাকে চিন্তা করতে হবে না; এক ধরণের উভয় ডেটার সেট একই সাথে পুনঃক্রম করে। এবং লেখার জন্য কোনও অতিরিক্ত কাঠামো নেই।
সিএওও

উত্তর:


118

একটি সাজানোর ক্রমানুসারে সন্ধান করা

এর std::vector<T>জন্য একটি এবং একটি তুলনা দেওয়া T, আমরা যদি আপনি এই তুলনাটি ব্যবহার করে ভেক্টরটিকে বাছাই করে থাকেন তবে আপনি যে ক্রমটি ব্যবহার করতেন তা সন্ধান করতে সক্ষম হতে চাই।

template <typename T, typename Compare>
std::vector<std::size_t> sort_permutation(
    const std::vector<T>& vec,
    Compare& compare)
{
    std::vector<std::size_t> p(vec.size());
    std::iota(p.begin(), p.end(), 0);
    std::sort(p.begin(), p.end(),
        [&](std::size_t i, std::size_t j){ return compare(vec[i], vec[j]); });
    return p;
}

একটি সাজানোর ক্রমানুসারে প্রয়োগ করা

একটি std::vector<T>এবং একটি আদেশ দেওয়া হয়েছে , আমরা অনুমতি std::vector<T>অনুসারে পুনরায় সাজানো একটি নতুন নির্মাণ করতে সক্ষম হতে চাই ।

template <typename T>
std::vector<T> apply_permutation(
    const std::vector<T>& vec,
    const std::vector<std::size_t>& p)
{
    std::vector<T> sorted_vec(vec.size());
    std::transform(p.begin(), p.end(), sorted_vec.begin(),
        [&](std::size_t i){ return vec[i]; });
    return sorted_vec;
}

আপনি অবশ্যই apply_permutationএকটি নতুন সাজানো অনুলিপি ফিরিয়ে দেওয়ার পরিবর্তে আপনি যে ভেক্টরটি দিয়েছেন তা পরিবর্তন করতে আপনি অবশ্যই পরিবর্তন করতে পারেন। এই পদ্ধতির এখনও লিনিয়ার সময় জটিলতা এবং আপনার ভেক্টরের আইটেম প্রতি এক বিট ব্যবহার করে। তাত্ত্বিকভাবে, এটি এখনও লিনিয়ার স্পেস জটিলতা; তবে, বাস্তবে, যখন sizeof(T)বড় হয় মেমরির ব্যবহার হ্রাস নাটকীয় হতে পারে। ( বিশদ দেখুন )

template <typename T>
void apply_permutation_in_place(
    std::vector<T>& vec,
    const std::vector<std::size_t>& p)
{
    std::vector<bool> done(vec.size());
    for (std::size_t i = 0; i < vec.size(); ++i)
    {
        if (done[i])
        {
            continue;
        }
        done[i] = true;
        std::size_t prev_j = i;
        std::size_t j = p[i];
        while (i != j)
        {
            std::swap(vec[prev_j], vec[j]);
            done[j] = true;
            prev_j = j;
            j = p[j];
        }
    }
}

উদাহরণ

vector<MyObject> vectorA;
vector<int> vectorB;

auto p = sort_permutation(vectorA,
    [](T const& a, T const& b){ /*some comparison*/ });

vectorA = apply_permutation(vectorA, p);
vectorB = apply_permutation(vectorB, p);

রিসোর্স


4
আমার সংকলকটিতে, আমাকে "তুলনা করুন এবং তুলনা করুন" "তুলনা তুলনা করুন" তে পরিবর্তন করতে হয়েছিল।
স্মৃতিচেস

4
এসটিডি :: আইওটা ফাংশন (বনাম ২০১২) চালানোর জন্য আমার শিরোনাম <সংখ্যার> অন্তর্ভুক্ত করা দরকার।
স্মিথ

4
" আপনি অবশ্যই apply_permutationনতুন সাজানো অনুলিপি ফিরিয়ে দেওয়ার পরিবর্তে আপনি যে ভেক্টরটি দিয়েছিলেন তা পরিবর্তন করতে আপনি পরিবর্তন করতে পারেন। " আমি কমপক্ষে ধারণা হিসাবে এটি উত্তরের জন্য একটি দরকারী সংযোজন খুঁজে পাব। আপনি কি apply_permutationনিজের মতো করে এটিকে বাস্তবায়ন করবেন ?
iljarn

4
@ildjarn আমি আপনার পরামর্শ দিয়ে উত্তর আপডেট করেছি।
টিমোথি শিল্ডস

4
চমৎকার স্নিপেট জন্য ধন্যবাদ! বাছাই_পরিবর্তন ঘোষণার কনস্টেন্ট Compare& compareহওয়া উচিত। অন্যথায় আপনি স্টাডি :: কম <টি> বা অনুরূপ ব্যবহার করতে পারবেন না।
কোটাকোটাকোট

9

সঙ্গে পরিসীমা-V3 , এটা সহজ, সাজানোর একটি জিপ দৃশ্য হল:

std::vector<MyObject> vectorA = /*..*/;
std::vector<int> vectorB = /*..*/;

ranges::v3::sort(ranges::view::zip(vectorA, vectorB));

বা স্পষ্টভাবে প্রজেকশন ব্যবহার করুন:

ranges::v3::sort(ranges::view::zip(vectorA, vectorB),
                 std::less<>{},
                 [](const auto& t) -> decltype(auto) { return std::get<0>(t); });

ডেমো


ভিএস2017-এ চেষ্টা করা হয়েছে, আমি যা চেষ্টা করেছি তা নির্ধারণ করে কিছুই সংকলিত বা কাজ করেছে না। এই লাইব্রেরিটি VS2019, GCC এবং LLVM এ কাজ করার জন্য পরিচিত।
কনটাঙ্গো

4

আমি যে এক্সটেনশানটি নিয়ে এসেছি তাতে অবদান রাখতে চাই। লক্ষ্যটি হ'ল একাধিক ভেক্টরকে একই সাথে একটি সাধারণ সিনট্যাক্স ব্যবহার করে বাছাই করতে সক্ষম।

sortVectorsAscending(criteriaVec, vec1, vec2, ...)

অ্যালগরিদম টিমোথি প্রস্তাবিত একইর মতো তবে বৈচিত্র্যমূলক টেম্পলেটগুলি ব্যবহার করে , তাই আমরা একই সাথে একাধিক ভেক্টরকে স্বেচ্ছাসেবী টাইপ করতে পারি।

কোড স্নিপেট এখানে:

template <typename T, typename Compare>
void getSortPermutation(
    std::vector<unsigned>& out,
    const std::vector<T>& v,
    Compare compare = std::less<T>())
{
    out.resize(v.size());
    std::iota(out.begin(), out.end(), 0);

    std::sort(out.begin(), out.end(),
        [&](unsigned i, unsigned j){ return compare(v[i], v[j]); });
}

template <typename T>
void applyPermutation(
    const std::vector<unsigned>& order,
    std::vector<T>& t)
{
    assert(order.size() == t.size());
    std::vector<T> st(t.size());
    for(unsigned i=0; i<t.size(); i++)
    {
        st[i] = t[order[i]];
    }
    t = st;
}

template <typename T, typename... S>
void applyPermutation(
    const std::vector<unsigned>& order,
    std::vector<T>& t,
    std::vector<S>&... s)
{
    applyPermutation(order, t);
    applyPermutation(order, s...);
}

template<typename T, typename Compare, typename... SS>
void sortVectors(
    const std::vector<T>& t,
    Compare comp,
    std::vector<SS>&... ss)
{
    std::vector<unsigned> order;
    getSortPermutation(order, t, comp);
    applyPermutation(order, ss...);
}

// make less verbose for the usual ascending order
template<typename T, typename... SS>
void sortVectorsAscending(
    const std::vector<T>& t,
    std::vector<SS>&... ss)
{
    sortVectors(t, std::less<T>(), ss...);
}

আইডিয়নে এটি পরীক্ষা করুন ।

আমি এই ব্লগ পোস্টে এটি একটু ভাল ব্যাখ্যা ।


3

অনুক্রমের সাহায্যে স্থানের বাছাই করা

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

কৌশলটি হ'ল শেষ সাজানোর ধাপে ডেটা ওভাররাইট করা তথ্যটি কোথায় রাখা উচিত তা জানতে বিলোপ এবং বিপরীত অনুমতি পেতে।

template <class K, class T> 
void sortByKey(K * keys, T * data, size_t size){
    std::vector<size_t> p(size,0);
    std::vector<size_t> rp(size);
    std::vector<bool> sorted(size, false);
    size_t i = 0;

    // Sort
    std::iota(p.begin(), p.end(), 0);
    std::sort(p.begin(), p.end(),
                    [&](size_t i, size_t j){ return keys[i] < keys[j]; });

    // ----------- Apply permutation in-place ---------- //

    // Get reverse permutation item>position
    for (i = 0; i < size; ++i){
        rp[p[i]] = i;
    }

    i = 0;
    K savedKey;
    T savedData;
    while ( i < size){
        size_t pos = i;
        // Save This element;
        if ( ! sorted[pos] ){
            savedKey = keys[p[pos]];
            savedData = data[p[pos]];
        }
        while ( ! sorted[pos] ){
            // Hold item to be replaced
            K heldKey  = keys[pos];
            T heldData = data[pos];
            // Save where it should go
            size_t heldPos = rp[pos];

            // Replace 
            keys[pos] = savedKey;
            data[pos] = savedData;

            // Get last item to be the pivot
            savedKey = heldKey;
            savedData = heldData;

            // Mark this item as sorted
            sorted[pos] = true;

            // Go to the held item proper location
            pos = heldPos;
        }
        ++i;
    }
}

4
এটি দেখতে O (N ^ 2) বলে মনে হলেও এটি তা নয়। আইটেমটি বাছাই না করা হলে অভ্যন্তরীণ সময়টি কেবলমাত্র কার্যকর করা হয়। অভ্যন্তরীণ হিসাবে ডেটা সাজানোর সময় এটি পুনরাবৃত্তির সময় বাইরের দিকে চলে যায় ...
এমটিসিএস

2
  1. আপনার পৃথক ভেক্টরগুলির মধ্যে জোড়গুলির একটি ভেক্টর তৈরি করুন। জোড়ের ভেক্টরটি
    আরম্ভ করুন
    জোড়ের ভেক্টর যুক্ত করা

  2. একটি কাস্টম সাজানোর তুলনা করুন:
    কাস্টম অবজেক্টগুলির ভেক্টর বাছাই করা হচ্ছে
    http://rosettacode.org/wiki/Sort_ using_a_custom_comparator#C.2B.2B

  3. আপনার জোড় জোড় বাছাই করুন।

  4. আপনার ভেক্টর জোড়গুলির পৃথক ভেক্টরগুলিতে পৃথক করুন।

  5. এই সমস্ত একটি ফাংশন মধ্যে রাখুন।

কোড:

std::vector<MyObject> vectorA;
std::vector<int> vectorB;

struct less_than_int
{
    inline bool operator() (const std::pair<MyObject,int>& a, const std::pair<MyObject,int>& b)
    {
        return (a.second < b.second);
    }
};

sortVecPair(vectorA, vectorB, less_than_int());

// make sure vectorA and vectorB are of the same size, before calling function
template <typename T, typename R, typename Compare>
sortVecPair(std::vector<T>& vecA, std::vector<R>& vecB, Compare cmp)
{

    std::vector<pair<T,R>> vecC;
    vecC.reserve(vecA.size());
    for(int i=0; i<vecA.size(); i++)
     {
        vecC.push_back(std::make_pair(vecA[i],vecB[i]);   
     }

    std::sort(vecC.begin(), vecC.end(), cmp);

    vecA.clear();
    vecB.clear();
    vecA.reserve(vecC.size());
    vecB.reserve(vecC.size());
    for(int i=0; i<vecC.size(); i++)
     {
        vecA.push_back(vecC[i].first);
        vecB.push_back(vecC[i].second);
     }
}

রেফারেন্স জোড়ের ভেক্টর?
মাকিং হাঁস

আপনি যা বলতে চাইছেন তা আমি পেয়েছি তবে জোড় উল্লেখগুলি সহজে কাজ করছে না।
রুবেন2020

4
@ রুবেন ২০২০: এটি করতে পারে তবে কেবল ব্যান্ড-এইড করে বিষয়টি ইস্যু করে। আপনার যদি দু'টি টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো টুকরো হয়ে থাকে যে একটিকে অন্যকে বাছাই করা উচিত তবে মনে হয় আপনার কাছে যা আছে তা হ'ল একটি-এখনও-সংহত বস্তু।
সিএওও

1

আমি ধরে নিচ্ছি যে ভেক্টর এবং ভেক্টরবির সমান দৈর্ঘ্য রয়েছে। আপনি অন্য ভেক্টর তৈরি করতে পারেন, আসুন একে পোস্ট করুন, যেখানে:

pos[i] = the position of vectorA[i] after sorting phase

এবং তারপরে, আপনি পোস ব্যবহার করে ভেক্টরবিকে বাছাই করতে পারেন, যেমন ভেক্টরবোর্ট করা যেখানে:

vectorBsorted[pos[i]] = vectorB[i]

এবং তারপরে ভেক্টরএসটি একই সূচকের যথাক্রমে ভেক্টরএ হিসাবে সাজানো হয়।


0

আমি নিশ্চিত না যে এটি কাজ করে কিনা তবে আমি এই জাতীয় কিছু ব্যবহার করব। উদাহরণস্বরূপ দুটি ভেক্টর বাছাই করার জন্য আমি উতরিত বুদ্বুদ সাজানোর পদ্ধতি এবং ভেক্টর জোড়া ব্যবহার করব।

উত্থিত বুদ্বুদ সাজানোর জন্য, আমি একটি ফাংশন তৈরি করব যা ভেক্টর জোড়া প্রয়োজন।

void bubbleSort(vector< pair<MyObject,int> >& a)
{
    bool swapp = true;
    while (swapp) {
        int key;
        MyObject temp_obj;
        swapp = false;
        for (size_t i = 0; i < a.size() - 1; i++) {
            if (a[i].first < a[i + 1].first) {
                temp_obj = a[i].first;
                key = a[i].second;

                a[i].first = a[i + 1].first;
                a[i + 1].first = temp_obj;

                a[i].second = a[i + 1].second;
                a[i + 1].second = key;

                swapp = true;
            }
        }
    }
}

এর পরে আমি আপনার 2 ভেক্টর মানগুলিকে একটি ভেক্টর জোড়ায় রেখে দেব। আপনি একই সাথে মান যুক্ত করতে সক্ষম হন তবে এটি ব্যবহার করুন এবং বুদ্বুদ বাছাই ফাংশন কল করুন।

vector< pair<MyObject,int> > my_vector;

my_vector.push_back( pair<MyObject,int> (object_value,int_value));

bubbleSort(my_vector);

আপনি যদি 2 টি ভেক্টর যুক্ত করার পরে মানগুলি ব্যবহার করতে চান তবে আপনি এটি ব্যবহার করতে পারেন এবং বুদ্বুদ বাছাই ফাংশনটি কল করতে পারেন।

vector< pair<MyObject,int> > temp_vector;

for (size_t i = 0; i < vectorA.size(); i++) {
            temp_vector.push_back(pair<MyObject,int> (vectorA[i],vectorB[i]));
        }

bubbleSort(temp_vector);

আশা করি এটা কাজে লাগবে. শুভেচ্ছা, ক্যানার


0

আমি সম্প্রতি একটি সঠিক জিপ পুনরুক্তি লিখেছি যা স্টিল অ্যালগরিদমের সাথে কাজ করে। এটি আপনাকে এই জাতীয় কোড তৈরি করতে দেয়:

std::vector<int> a{3,1,4,2};
std::vector<std::string> b{"Alice","Bob","Charles","David"};

auto zip = Zip(a,b);
std::sort(zip.begin(), zip.end());

for (const auto & z: zip) std::cout << z << std::endl;

এটি একটি একক শিরোনামে রয়েছে এবং কেবলমাত্র প্রয়োজন সি ++ 17। এটি গিটহাবে পরীক্ষা করে দেখুন ।

কোডেরভিউতে একটি পোস্ট রয়েছে যাতে সমস্ত উত্স কোড রয়েছে।


0

টিমোথি শিল্ডস উত্তর উপর ভিত্তি করে।
একটি ছোট ঝাঁকুনির সাহায্যে apply_permutaionআপনি ভাঁজ প্রকাশের ব্যবহারের সাথে এক সাথে একই সাথে বিভিন্ন ধরণের একাধিক ভেক্টরকে অনুমতিটি প্রয়োগ করতে পারেন।

template <typename T, typename... Ts>
void apply_permutation(const std::vector<size_t>& perm, std::vector<T>& v, std::vector<Ts>&... vs) {

    std::vector<bool> done(v.size());
    for(size_t i = 0; i < v.size(); ++i) {
        if(done[i]) continue;
        done[i] = true;
        size_t prev = i;
        size_t curr = perm[i];
        while(i != curr) {
            std::swap(v[prev], v[curr]);
            (std::swap(vs[prev], vs[curr]), ...);
            done[curr] = true;
            prev = curr;
            curr = perm[curr];
        }
    }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.