কোনও ভেক্টর থেকে সাবভেেক্টর উত্তোলনের সর্বোত্তম উপায়?


295

ধরুন আমার আকারের একটি std::vector(আসুন এটি কল করুন myVec) আছে N। Y এর মাধ্যমে এক্স উপাদানগুলির একটি অনুলিপি সহ নতুন ভেক্টর তৈরির সহজ উপায় কী, যেখানে 0 <= এক্স <= ওয়াই <= এন-1? উদাহরণস্বরূপ, আকারের ভেক্টর myVec [100000]মাধ্যমে ।myVec [100999]150000

এটি যদি কোনও ভেক্টরের সাথে দক্ষতার সাথে করা যায় না, তবে এর পরিবর্তে আমার আর কোন এসটিএল ডেটাটাইপ ব্যবহার করা উচিত?


7
আপনি বলেছিলেন যে আপনি সাবভেেক্টরটি বের করতে চান তবে আমার কাছে মনে হচ্ছে আপনি যা চান তা হ'ল সাবভেেক্টরটির একটি ভিউ / অ্যাক্সেস - পার্থক্য হ'ল কোনও ভিউ অনুলিপি করবে না - পুরানো স্কুল সি ++ স্টার্ট পয়েন্টার এবং শেষ পয়েন্টার ব্যবহার করা হবে, একটি std :: ভেক্টরের সাথে মেম্বুটি সংগত, তবে আপনার পয়েন্টার ব্যবহার করে পুনরাবৃত্তি করা সম্ভব হবে এবং এর ফলে অনুলিপি করা এড়ানো সম্ভব হবে, তবে যদি আপনি অনুলিপি মানা না করেন তবে কেবল আপনার পূর্ববর্তী ক্ষেত্রের সাথে একটি নতুন ভেক্টর আরম্ভ করুন ভেক্টর
সার্প

সি ++ 11 সাল থেকে .data () ( cplusplus.com/references/vector/vector/data ) রয়েছে। যাইহোক, পয়েন্টার ব্যবহার Stl পাত্রে মধ্যে নিরুৎসাহিত করা হয়, দেখতে stackoverflow.com/questions/31663770/...
ডেভিড টথ

উত্তর:


371
vector<T>::const_iterator first = myVec.begin() + 100000;
vector<T>::const_iterator last = myVec.begin() + 101000;
vector<T> newVec(first, last);

নতুন ভেক্টরটি নির্মাণের জন্য এটি একটি (এন) অপারেশন, তবে এর চেয়ে ভাল উপায় আর নেই।


12
+1, এছাড়াও এটি ও (ওয়াইএক্স), যা ও (এন) এর চেয়ে কম বা সমান (এবং তার উদাহরণে অনেক কম)
অরিপ

74
@ ওরিপ ভাল, তবে এটি সর্বোপরি ও (এন)
জোহান গেরেল

55
@ গ্রেগরোজারস: বি-ও সংকেত যেখানে এন নির্দিষ্ট নম্বর রয়েছে তা ব্যবহার করার কোনও অর্থ নেই। বিগ-ও এন কীভাবে পরিবর্তিত হয় সে সম্পর্কে প্রবৃদ্ধির হারকে যোগাযোগ করে। জোহান: একটি পরিবর্তনশীল নাম দুটি উপায়ে ব্যবহার না করাই ভাল। আমরা সাধারণত বলতে হয় O(Y-X), বা আমরা বলতে চাই O(Z) where Z=Y-X
মাকিং হাঁস

2
@ গ্রেগরোজার্স এইভাবে ব্যবহার করে আমাদের একটি নতুন ভেক্টর ঘোষণা করা দরকার। আসল ভেক্টর পরিবর্তন করার কোনও উপায় আছে কি? মাইভেকের মতো কিছু (প্রথম, শেষ)? আমি জানি এটি ভুল, তবে আমার কোডগুলিতে পুনরাবৃত্তি ব্যবহার করতে চাইলে আমার সমাধানটি সত্যই দরকার এবং বার বার একই ভেক্টর ব্যবহার করা প্রয়োজন (যদিও পরিবর্তিত)। ধন্যবাদ!
ulyssis2

13
শুধু কেন নয় vector<T> newVec(myVec.begin() + 100000, myVec.begin() + 101000);?
অ্যাকুইটার্টল্টেল

88

কেবল ভেক্টর কনস্ট্রাক্টর ব্যবহার করুন।

std::vector<int>   data();
// Load Z elements into data so that Z > Y > X

std::vector<int>   sub(&data[100000],&data[101000]);

2
ঠিক আছে, আমি বুঝতে পারি না যে একটি স্বেচ্ছাচারী ভেক্টর উপাদান থেকে একটি পুনরাবৃত্তি প্রাপ্ত করা সহজ simple
অ্যানড্রু

5
এই ভেক্টর উপাদানগুলির ঠিকানা নেওয়া একটি অপ্রয়োজনীয় হ্যাক যা ভেক্টর স্টোরেজটি যথাযথভাবে সামঞ্জস্যপূর্ণ না হলে ভেঙে যাবে। শুরু () + 100000 ইত্যাদি ব্যবহার করুন
j_random_hacker

2
আমার খারাপ, আপাতদৃষ্টিতে স্ট্যান্ডার্ড গ্যারান্টি দেয় যে ভেক্টর স্টোরেজটি সামঞ্জস্যপূর্ণ। তবুও এটির মতো ঠিকানাগুলির সাথে কাজ করা খারাপ অভ্যাস কারণ এটি অবশ্যই () + 100000 শুরু হওয়ার সাথে সাথে এলোমেলো অ্যাক্সেস সমর্থনকারী সমস্ত ধারকগুলির পক্ষে কাজ করার নিশ্চয়তা দেয় না।
j_random_hacker

33
@ জেআর্যান্ডম_হ্যাকার: দুঃখিত দ্বিমত পোষণ করতে হবে। এই ধরণের পদ্ধতি সমর্থন করার জন্য স্ট্যান্ড :: ভেক্টরের জন্য এসটিএল স্পেসিফিকেশন স্পষ্টভাবে পরিবর্তন করা হয়েছিল। এছাড়াও একটি পয়েন্টারটি বৈধ ধরণের পুনরুক্তিযোগ্য। পুনরাবৃত্তিকারীদের অনুসন্ধান করুন <>
মার্টিন ইয়র্ক

6
@ taktak004 না। মনে রাখবেন যে operator[]একটি রেফারেন্স দেয়। আপনি কেবল রেফারেন্সটি পড়তে বা লিখতে পারা এটিই কেবল অ্যাক্সেস লঙ্ঘনে পরিণত হবে। যেহেতু আমরা দু'টিই করি না বরং পরিবর্তে ঠিকানাটি পাই আমরা ইউবিকে অনুরোধ করি নি, ,.
মার্টিন ইয়র্ক

28

std::vector<T>(input_iterator, input_iterator), আপনার ক্ষেত্রে foo = std::vector<T>(myVec.begin () + 100000, myVec.begin () + 150000);, উদাহরণস্বরূপ এখানে দেখুন


1
যেহেতু অ্যান্ড্রু একটি নতুন ভেক্টর নির্মাণের চেষ্টা করছে, তাই আমি "fd = std :: vector (..."
ড্রু ডোরম্যান

4
হ্যাঁ, অবশ্যই, তবে আপনি টাইপ করুন std :: ভেক্টর <int> foo = std :: ভেক্টর (...) বা স্টাড :: ভেক্টর <int> foo (...) কোনও বিষয় নয়।
আন্টেরু

19

আজকাল, আমরা spanএস ব্যবহার ! সুতরাং আপনি লিখতে হবে:

#include <gsl/span>

...
auto start_pos = 100000;
auto length = 1000;
auto span_of_myvec = gsl::make_span(myvec);
auto my_subspan = span_of_myvec.subspan(start_pos, length);

এর একই ধরণের 1000 উপাদানের স্প্যান পেতে myvec। বা আরও সংক্ষিপ্ত রূপ:

auto my_subspan = gsl::make_span(myvec).subspan(1000000, 1000);

(তবে আমি এটি এতটা পছন্দ করি না, যেহেতু প্রতিটি সংখ্যার যুক্তির অর্থ সম্পূর্ণ পরিষ্কার নয়; এবং দৈর্ঘ্য এবং শুরুর_পোস একই আকারের হয় তবে এটি আরও খারাপ হয়))

যাইহোক, মনে রাখবেন যে এটি কোনও অনুলিপি নয়, এটি কেবল ভেক্টরের ডেটা দেখার জন্য, তাই সাবধান হন। আপনি যদি সত্যিকারের অনুলিপি চান তবে আপনি এটি করতে পারেন:

std::vector<T> new_vec(my_subspan.cbegin(), my_subspan.cend());

মন্তব্য:


ব্যবহার করেন cbeginএবং cend); শুধু নীতি জন্য std::cbeginএমনকি ইত্যাদি।
JHBonarius

1
@ জেএইচবিওনারিয়াস: কনটেইনারটি বেছে নেওয়ার ক্ষেত্রে এই কোডটি কীভাবে প্রলম্বিত হয় না তা দেখে আমি কোনও বিশেষ সুবিধা পাচ্ছি না; আমি মনে করি স্বাদের বিষয়।
einpoklum

10

উভয় পরিবর্তন করা যাচ্ছে না তাহলে (কোন যোগ / আইটেম মোছার - বিদ্যমান বেশী পরিবর্তন যতদিন আপনি থ্রেডিং সমস্যার বোঝে না জরিমানা), আপনি কেবল প্রায় পাস করতে পারেন data.begin() + 100000এবং data.begin() + 101000, এবং দাবী করে যে, তারা begin()এবং end()একটি ছোট ভেক্টরের।

বা, যেহেতু ভেক্টর স্টোরেজটি সামঞ্জস্যপূর্ণ হওয়ার গ্যারান্টিযুক্ত, আপনি কেবলমাত্র 1000 আইটেম অ্যারে পেরিয়ে যেতে পারেন:

T *arrayOfT = &data[0] + 100000;
size_t arrayOfTLength = 1000;

এই দুটি কৌশলই ধ্রুবক সময় নেয়, তবে তথ্যের দৈর্ঘ্য বৃদ্ধি না হওয়া, পুনরায় স্থান নির্ধারণের প্রয়োজন হয়।


আপনি যদি মূল ভেক্টর এবং সাবভেক্টরকে সংযুক্ত করতে চান তবে এটিও ভাল।
পাইরুলেজ

7

এই আলোচনাটি বেশ পুরানো তবে তালিকা-সূচনা সহ সহজতমটি এখনও উল্লেখ করা হয়নি :

 vector<int> subvector = {big_vector.begin() + 3, big_vector.end() - 2}; 

এর জন্য সি ++ 11 বা তারও বেশি প্রয়োজন।

ব্যবহারের উদাহরণ:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main(){

    vector<int> big_vector = {5,12,4,6,7,8,9,9,31,1,1,5,76,78,8};
    vector<int> subvector = {big_vector.begin() + 3, big_vector.end() - 2};

    cout << "Big vector: ";
    for_each(big_vector.begin(), big_vector.end(),[](int number){cout << number << ";";});
    cout << endl << "Subvector: ";
    for_each(subvector.begin(), subvector.end(),[](int number){cout << number << ";";});
    cout << endl;
}

ফলাফল:

Big vector: 5;12;4;6;7;8;9;9;31;1;1;5;76;78;8;
Subvector: 6;7;8;9;9;31;1;1;5;76;

6

আপনি কী ধরণের তা উল্লেখ করেননি std::vector<...> myVec, তবে এটি যদি কোনও সাধারণ টাইপ বা স্ট্রাক্ট / শ্রেণি যেখানে পয়েন্টারগুলি অন্তর্ভুক্ত না থাকে এবং আপনি সর্বোত্তম দক্ষতা চান তবে আপনি একটি সরাসরি মেমরি অনুলিপি করতে পারেন (যা আমি মনে করি এটির চেয়ে দ্রুত হবে) অন্যান্য উত্তর সরবরাহ করা হয়েছে)। এই ক্ষেত্রে std::vector<type> myVecযেখানে এটির জন্য এখানে একটি সাধারণ উদাহরণ typeরয়েছে int:

typedef int type; //choose your custom type/struct/class
int iFirst = 100000; //first index to copy
int iLast = 101000; //last index + 1
int iLen = iLast - iFirst;
std::vector<type> newVec;
newVec.resize(iLen); //pre-allocate the space needed to write the data directly
memcpy(&newVec[0], &myVec[iFirst], iLen*sizeof(type)); //write directly to destination buffer from source buffer

2
আমি ভাবছি যদি -O3, @ আন্টেরুর "কনস্ট্রাক্টর ব্যবহার করে" std::vector(myVec.begin () + 100000, myVec.begin () + 150000);দিয়ে এই উত্পাদনের আর-সংস্করণটি ঠিক একই সমাবেশে না ঘটে?
স্যান্ডথর্ন

1
এমএসভিসি ++ ২০১৫, উদাহরণস্বরূপ, উপযুক্ত হলে এটি সংকলন std::vector<>(iter, iter)করে memmove()(যদি কনস্ট্রাক্টর তুচ্ছ, তুচ্ছ এর উপযুক্ত সংজ্ঞায়নের জন্য)।
পাবলো এইচ

1
ফোন করবেন না memcpy। এমন একটি std::copyবা কোনও কনস্ট্রাক্টর করুন যা কোনও পরিসীমা গ্রহণ করে (দুটি পুনরাবৃত্তকারী), এবং সংকলক এবং std.library memcpyযখন উপযুক্ত হবে তখন কল করার জন্য ষড়যন্ত্র করবে ।
বুলেটম্যাগনেট


3

এম সাবভেেক্টরের আকার হয়ে গেলে আপনি ও (এম) পারফরম্যান্সের সাথে এসটিএল অনুলিপিটি ব্যবহার করতে পারেন ।


উত্সাহিত হয়েছে কারণ এটি আমাকে সঠিক দিকে নির্দেশ করেছে তবে আমি দেখতে পাচ্ছি যে @ লোকিস্টারি প্রস্তাব দেয় কেন এটি সঠিক পছন্দ নয় - যেহেতু এসটিএল :: অনুলিপি দুটি মাপের :: ভেক্টর <টি> একই আকার এবং প্রকারের অ্যারে নিয়ে কাজ করে। ওপি'র পোস্টে এখানে উল্লিখিত হিসাবে ওপি একটি নতুন অনুচ্ছেদে একটি ছোট ছোট অ্যারেতে একটি অনুচ্ছেদ অনুলিপি করতে চায়: "0 <= x <= Y <= N-1"
অ্যান্ড্রু

@ অ্যান্ড্রু, দেখুন স্ট্যান্ড :: কপি এবং এসটিডি :: ব্যাক_ইনসেটর ব্যবহার করে
6:53 এ ক্রিসগ

@ লোকী আস্তারি কেন নয়?
6:54 এ ক্রিসিং করুন

2
@ লোকিআস্তারি আমি এই সম্পাদনার কথা উল্লেখ করছিলাম যা পিয়ার পর্যালোচনা থেকে বাঁচেনি, যা উদাহরণটি তুলে ধরেছে <br/> ভেক্টর <টি> নতুনকে; std :: copy (myvec.begin () + 10000, myvec.begin () +10100, std :: back_inserter (newvec)); <br/> এক্ষেত্রে আপনাকে প্রথমে গন্তব্য তৈরি করার দরকার নেই, তবে নিশ্চিত, সরাসরি সূচনা আরও ... প্রত্যক্ষ।
খ্রিস্ট

1
@ ক্রিসগ: এটি দুটি লাইনও। এটি দক্ষ কিনা তা নিশ্চিত করার জন্য আপনাকে তৃতীয় লাইন আটকে রাখতে হবে। newvec.reserve(10100 - 10000);। আইটি অবশ্যই একটি বিকল্প এবং প্রযুক্তিগতভাবে এটি কাজ করবে। তবে দু'জনের মধ্যে কোনটি আপনি সুপারিশ করতে যাচ্ছেন?
মার্টিন ইয়র্ক 21

1

রৈখিক সময় নয় এমন একটি সংগ্রহের প্রকল্পের একমাত্র উপায় হ'ল অলসভাবে কাজ করা, যেখানে ফলস্বরূপ "ভেক্টর" আসলে একটি উপপ্রকার যা মূল সংগ্রহের জন্য প্রতিনিধিত্ব করে। উদাহরণস্বরূপ, স্কালার List#subseqপদ্ধতিটি ধ্রুবক সময়ে একটি উপ-অনুক্রম তৈরি করে। তবে, এটি কেবল তখনই কাজ করতে পারে যদি সংগ্রহটি পরিবর্তনযোগ্য এবং যদি অন্তর্নিহিত ভাষা ক্রীড়া জঞ্জাল সংগ্রহ।


সি ++ উপায়ে এটি করা হবে এক্স-এর ভেক্টরের পরিবর্তে এক্স-তে ভাগ করা_পিটারের ভেক্টর থাকা এবং তারপরে এসপিগুলি অনুলিপি করা, তবে দুর্ভাগ্যক্রমে আমি মনে করি না এটি দ্রুততর কারণ এসপি সিপি করার সাথে জড়িত পারমাণবিক অপারেশন। বা আসল ভেক্টর পরিবর্তে ভেক্টরের কনস্ট শেয়ারড_পিটার হতে পারে এবং আপনি কেবল এটি সাব্রাইং করার জন্য রেফারেন্স গ্রহণ করেন। ofc আপনাকে এটিকে ভেক্টরটির একটি শেয়ার্ড_পিটার তৈরি করার দরকার নেই তবে আপনার আজীবন সমস্যা আছে ... আমার মাথার উপরে এই সমস্ত কিছুই ভুল হতে পারে ...
NoSenseEtAl

0

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

std::vector <int>   myVec;
int *p;
// Add some data here and set start, then
p=myVec.data()+start;

তারপরে পয়েন্টার পি এবং সাবউেক্টরটির প্রয়োজন মতো যে কোনও কিছুতে একটি লেন পাস করুন।

নোটলেন অবশ্যই হবে !! len < myVec.size()-start


এটি একটি অনুলিপি সম্পাদন করে না।
30:38

0

হয়তো array_view / বিঘত GSL গ্রন্থাগার একটি ভাল বিকল্প।

এখানে একটি একক ফাইল বাস্তবায়নও রয়েছে: অ্যারে_ভিউ


দয়া করে এখানে লিঙ্কের সাথে উত্তর যুক্ত করুন। যেহেতু বাহ্যিক লিঙ্কটি ভবিষ্যতে পরিবর্তিত হতে পারে
প্যান্থার

0

একটি ভেক্টর থেকে অন্য ভেক্টরে সহজেই উপাদানগুলি অনুলিপি করুন
এই উদাহরণে, আমি এটি বোঝা সহজ করার জন্য জোড়গুলির একটি ভেক্টর ব্যবহার করছি
`

vector<pair<int, int> > v(n);

//we want half of elements in vector a and another half in vector b
vector<pair<lli, lli> > a(v.begin(),v.begin()+n/2);
vector<pair<lli, lli> > b(v.begin()+n/2, v.end());


//if v = [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]
//then a = [(1, 2), (2, 3)]
//and b = [(3, 4), (4, 5), (5, 6)]

//if v = [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7)]
//then a = [(1, 2), (2, 3), (3, 4)]
//and b = [(4, 5), (5, 6), (6, 7)]

'
আপনি দেখতে পাচ্ছেন যে আপনি সহজেই একটি ভেক্টর থেকে অন্য ভেক্টরে উপাদানগুলি অনুলিপি করতে পারেন, উদাহরণস্বরূপ আপনি যদি সূচী 10 থেকে 16 পর্যন্ত উপাদানগুলি অনুলিপি করতে চান তবে আমরা ব্যবহার করব

vector<pair<int, int> > a(v.begin()+10, v.begin+16);

এবং যদি আপনি সূচক 10 থেকে শুরু করে কিছু সূচি পর্যন্ত উপাদানগুলি চান তবে সেই ক্ষেত্রে

vector<pair<int, int> > a(v.begin()+10, v.end()-5);

আশা করি এটি সাহায্য করে, শুধু শেষ ক্ষেত্রে মনে রাখবেন v.end()-5 > v.begin()+10


0

তবুও অন্য বিকল্প: উদাহরণস্বরূপ কার্যকর যখন thrust::device_vectorএবং ক এর মধ্যে চলতে থাকে thrust::host_vector, যেখানে আপনি কনস্ট্রাক্টর ব্যবহার করতে পারবেন না।

std::vector<T> newVector;
newVector.reserve(1000);
std::copy_n(&vec[100000], 1000, std::back_inserter(newVector));

জটিলতা ও (এন) হওয়া উচিত

আপনি শীর্ষ অ্যাওয়ার্ড কোডের সাথে এটি একত্রিত করতে পারেন

vector<T>::const_iterator first = myVec.begin() + 100000;
vector<T>::const_iterator last = myVec.begin() + 101000;
std::copy(first, last, std::back_inserter(newVector));
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.