এসটিএল ধারক ফিল্টার করার আধুনিক উপায়?


98

সি # এর কয়েক বছর পরে সি ++ এ ফিরে আসছিলাম আমি ভাবছিলাম যে আধুনিক - পড়ুন: সি ++ 11 - অ্যারের ফিল্টার করার পদ্ধতিটি কীভাবে হবে, অর্থাৎ আমরা কীভাবে এই লিনকের প্রশ্নের অনুরূপ কিছু অর্জন করতে পারি:

var filteredElements = elements.Where(elm => elm.filterProperty == true);

উপাদানগুলির একটি ভেক্টর ফিল্টার করার জন্য ( stringsএই প্রশ্নের খাতিরে)?

আমি আন্তরিকভাবে আশা করি যে পুরাতন এসটিএল স্টাইলের অ্যালগরিদমগুলি (বা এমনকি এক্সটেনশনগুলি boost::filter_iterator) সংজ্ঞায়িত করার জন্য সুস্পষ্ট পদ্ধতিগুলির প্রয়োজনীয়তা এখনই ছাড়িয়ে গেছে?


এটি filterPropertyসেট করা সমস্ত উপাদান পুনরুদ্ধার করে true?
জোসেফ ম্যানসফিল্ড

দুঃখিত, হ্যাঁ কিছু জেনেরিক ফিল্টার মানদণ্ড ..
এটিভি

4
কিছু লাইব্রেরি রয়েছে যা নেট। লিনক ++ এবং সিপ্পলিংক এর লিনকিউ পদ্ধতিগুলি অনুকরণ করার চেষ্টা করে । আমি তাদের সাথে কাজ করি নি তবে আমার ধারণা তারা এসটিএল পাত্রে সমর্থন করে।
ডার্ক

4
আপনি কী চান সে সম্পর্কে আপনার আরও স্পষ্ট হওয়া উচিত, যেহেতু সি ++ এবং সি # উভয় ক্ষেত্রেই উপযুক্ত লোকের সেট ছোট। আপনি এটি করতে চান তা বর্ণনা করুন।
ইয়াক্ক - অ্যাডাম নেভ্রামুমন্ট

উত্তর:


117

এর জন্য সিপ্লুপ্লাস.কম থেকে উদাহরণটি দেখুন std::copy_if:

std::vector<int> foo = {25,15,5,-5,-15};
std::vector<int> bar;

// copy only positive numbers:
std::copy_if (foo.begin(), foo.end(), std::back_inserter(bar), [](int i){return i>=0;} );

std::copy_iffooএখানে প্রতিটি উপাদানের জন্য ল্যাম্বডা এক্সপ্রেশনটি মূল্যায়ন করে এবং যদি trueএটি প্রদান করে তবে মানটি অনুলিপি করে bar

std::back_inserterআমাদের আসলে শেষে নতুন উপাদান সন্নিবেশ করতে পারেন bar(ব্যবহার push_back()প্রয়োজনীয় মাপ এটি প্রথম মাপ পরিবর্তন না করেও) একজন পুনরুক্তিকারীর সঙ্গে।


30
এটি কি লিনকিউয়ের সবচেয়ে কাছের যেটি সি ++ অফার করে? এটি আগ্রহী (আইডাব্লু অলস নয়), এবং খুব ভার্জোজ।
usr ডিরেক্টরির

4
@ এর আইএমও সিনট্যাকটিক চিনি, লুপের জন্য একটি সহজ কাজটি পাশাপাশি কাজ করে (এবং প্রায়শই একজন অনুলিপি এড়াতে দেয়)।
সেবাস্তিয়ান হফম্যান

4
ওপিএস উদাহরণটিতে কোনও লিনকিউ সিনট্যাকটিক চিনি ব্যবহার করা হয় না। সুবিধাগুলি অলস মূল্যায়ন এবং সামঞ্জস্যযোগ্যতা।
usr ডিরেক্টরির

4
@ ইউএসআর যা এখনও একটি সরল লুপ দ্বারা সহজেই অর্জন করা যায় std::copy_ifএটি কোনও লুপের চেয়ে বেশি নয়
সেবাস্তিয়ান হফম্যান

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

47

আরও কার্যকর পন্থা, যদি আপনার তালিকার নতুন কপিটির প্রয়োজন না হয় তবে এটি হ'ল remove_ifমূল ধারক থেকে উপাদানগুলি সরিয়ে দেয়।


7
@ATV আমি remove_ifবিশেষত পছন্দ করি কারণ পরিবর্তনের উপস্থিতিতে ফিল্টার ব্যবহার করার উপায় এটি সম্পূর্ণ নতুন তালিকার অনুলিপি করার চেয়ে দ্রুত। আমি যদি সি ++ এ ফিল্টার করছিলাম তবে আমি এটি ব্যবহার copy_ifকরব, সুতরাং আমার মনে হয় এটি যুক্ত হয়।
djhaskin987

16
ভেক্টরের জন্য, কমপক্ষে, remove_ifপরিবর্তন করে না size()আপনার সাথে শৃঙ্খল এটা করতে হবে eraseযে জন্য
রায়পুমান

4
@ ইরপুমান হ্যাঁ .. মুছুন / সরান। আর একটি সৌন্দর্য যা ঘন ঘন আমাকে অনুভব করে যে আমি এই দিনগুলিতে C ++ (আধুনিক ভাষাগুলির বিপরীতে) কাজ করার সময় কোনও টেপের ছিদ্র
এটিভি

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

31

সি ++ ২০ এ, রেঞ্জ লাইব্রেরি থেকে ফিল্টার দর্শন ব্যবহার করুন: (প্রয়োজনীয় #include <ranges>)

// namespace views = std::ranges::views;
vec | views::filter([](int a){ return a % 2 == 0; })

অলসভাবে এমনকি উপাদানগুলিকে ফেরত দেয় vec

( [পরিসীমা.এডাপ্টর.অবজেক্ট] / ৪ এবং [রেঞ্জ.ফিল্টার] দেখুন )


এটি ইতিমধ্যে জিসিসি 10 ( লাইভ ডেমো ) দ্বারা সমর্থিত । ঝনঝন এবং জিসিসি পুরোনো সংস্করণগুলি জন্য, মূল পরিসীমা-V3 গ্রন্থাগার খুব ব্যবহার করা যাবে, সঙ্গে #include <range/v3/view/filter.hpp>(বা #include <range/v3/all.hpp>) এবং ranges::viewsপরিবর্তে নামস্থান std::ranges::views( লাইভ ডেমো )।


আপনার উত্তরটি সংকলিত করার জন্য আপনার # অন্তর্ভুক্ত করা উচিত এবং নামের স্থানটি ব্যবহার করা উচিত। এছাড়াও, কোন সংকলক আজকে এটি সমর্থন করে?
জিএসিমার্ড

4
@ জিসমার্ড এখন আরও ভাল?
এলএফ

4
যদি কেউ ম্যাকোজে এটি করার চেষ্টা করে: 2020 সালের মে পর্যন্ত, লাইবসি ++ এটি সমর্থন করে না।
ডেক্স

25

আমি মনে করি বুস্ট.রেঞ্জ একটি উল্লেখও প্রাপ্য। ফলাফলের কোডটি মূলটির থেকে বেশ কাছাকাছি:

#include <boost/range/adaptors.hpp>

// ...

using boost::adaptors::filtered;
auto filteredElements = elements | filtered([](decltype(elements)::value_type const& elm)
    { return elm.filterProperty == true; });

একমাত্র ক্ষতিটি ল্যাম্বদার প্যারামিটার ধরণের স্পষ্টভাবে ঘোষণা করতে হচ্ছে। আমি ডিক্লাইপ (উপাদানগুলি) :: মান_প্রকার ব্যবহার করেছি কারণ এটি সঠিক ধরণের বানান করা এড়িয়ে যায় এবং উদারতার শস্যও যুক্ত করে। বিকল্পভাবে, সি ++ 14 এর পলিমারফিক ল্যাম্বডাস সহ, প্রকারটি সহজেই অটো হিসাবে নির্দিষ্ট করা যেতে পারে:

auto filteredElements = elements | filtered([](auto const& elm)
    { return elm.filterProperty == true; });

ফিল্টারডিলিন্টস ট্র্যাভারসালের জন্য উপযুক্ত একটি ব্যাপ্তি হবে তবে এটি মূলত মূল ধারকটির একটি দৃশ্য। আপনার যা প্রয়োজন তা যদি মানদণ্ডগুলি সন্তুষ্ট করে এমন উপাদানগুলির অনুলিপিগুলিতে ভরা অন্য ধারক (যাতে এটি মূল ধারকটির জীবনকাল থেকে স্বতন্ত্র) থাকে তবে এটি দেখতে দেখতে দেখতে এটি হতে পারে:

using std::back_inserter; using boost::copy; using boost::adaptors::filtered;
decltype(elements) filteredElements;
copy(elements | filtered([](decltype(elements)::value_type const& elm)
    { return elm.filterProperty == true; }), back_inserter(filteredElements));

12

সি + এর সমতুল্য সি ++ এর জন্য আমার পরামর্শ

var filteredElements = elements.Where(elm => elm.filterProperty == true);

ফিল্টারিং করতে আপনি কোনও ল্যাম্বডা প্রিকিটকে পাস করেন এমন কোনও টেম্পলেট ফাংশনটি সংজ্ঞায়িত করুন। টেমপ্লেট ফাংশন ফিল্টার করা ফলাফল দেয়। যেমন:

template<typename T>
vector<T> select_T(const vector<T>& inVec, function<bool(const T&)> predicate)
{
  vector<T> result;
  copy_if(inVec.begin(), inVec.end(), back_inserter(result), predicate);
  return result;
}

ব্যবহার করতে - একটি তুচ্ছ উদাহরণ দেওয়া:

std::vector<int> mVec = {1,4,7,8,9,0};

// filter out values > 5
auto gtFive = select_T<int>(mVec, [](auto a) {return (a > 5); });

// or > target
int target = 5;
auto gt = select_T<int>(mVec, [target](auto a) {return (a > target); });

11

আন্ডারস্কোর-ডি পরামর্শ অনুসরণ করে উন্নত pjm কোড :

template <typename Cont, typename Pred>
Cont filter(const Cont &container, Pred predicate) {
    Cont result;
    std::copy_if(container.begin(), container.end(), std::back_inserter(result), predicate);
    return result;
}

ব্যবহার:

std::vector<int> myVec = {1,4,7,8,9,0};

auto filteredVec = filter(myVec, [](int a) { return a > 5; });
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.