নেস্টেড লুপগুলির আরও দ্রুত বিকল্প?


85

আমার সংখ্যার সংমিশ্রনের একটি তালিকা তৈরি করা দরকার। সংখ্যার বেশ ছোট, তাই আমি ব্যবহার করতে পারেন byteবদলে int। তবে প্রতিটি সম্ভাব্য সংমিশ্রণ পেতে এর জন্য অনেক নেস্টেড লুপ প্রয়োজন। আমি ভাবছি যে আমার পরে যা করার আরও কার্যকর উপায় আছে কিনা। এখন পর্যন্ত কোডটি হ'ল:

var data = new List<byte[]>();
for (byte a = 0; a < 2; a++)
for (byte b = 0; b < 3; b++)
for (byte c = 0; c < 4; c++)
for (byte d = 0; d < 3; d++)
for (byte e = 0; e < 4; e++)
for (byte f = 0; f < 3; f++)
for (byte g = 0; g < 3; g++)
for (byte h = 0; h < 4; h++)
for (byte i = 0; i < 2; i++)
for (byte j = 0; j < 4; j++)
for (byte k = 0; k < 4; k++)
for (byte l = 0; l < 3; l++)
for (byte m = 0; m < 4; m++)
{
    data.Add(new [] {a, b, c, d, e, f, g, h, i, j, k, l, m});
}

আমি এর মতো কিছু ব্যবহার করার BitArrayকথা ভাবছিলাম তবে আমি কীভাবে এটি যুক্ত করতে পারি তা নিশ্চিত নই।

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

দ্রুত পয়েন্টগুলির যুগল সম্পাদনা করুন (এবং ক্ষমাপ্রার্থী আমি এগুলি মূল পোস্টে রাখি না):

  • তাদের সংখ্যা এবং ক্রম (2, 3, 4, 3, 4, 3, 3 ইত্যাদি) খুব গুরুত্বপূর্ণ, সুতরাং লিনকিউ ব্যবহার করে পারমুটেশন জেনারেট করার মতো সমাধান ব্যবহার করা উপকারে আসবে না কারণ প্রতিটি 'কলামে' সর্বাধিক হয় বিভিন্ন
  • আমি গণিতবিদ নই, তাই আমি যদি 'ক্রমীকরণ' এবং 'সংমিশ্রণের' মতো প্রযুক্তিগত পদটি সঠিকভাবে ব্যবহার না করি তবে আমি ক্ষমা চাইছি :)
  • আমি না আমি শুধু একটা দখল করতে পারবে না বা অন্য একটি সূচক উপর ভিত্তি করে - একবারে এই সমাহারের সব পূরণ করতে প্রয়োজন
  • ব্যবহার byteকরা ব্যবহারের চেয়ে দ্রুততর int, আমি এটির গ্যারান্টি দিচ্ছি । ইনটগুলির চেয়ে 67 মিটার + অ্যারে বাইট থাকা মেমরির ব্যবহারে এটি আরও অনেক ভাল
  • আমার চূড়ান্ত লক্ষ্য এখানে নেস্টেড লুপগুলির জন্য একটি দ্রুত বিকল্পের সন্ধান করা।
  • আমি সমান্তরাল প্রোগ্রামিং ব্যবহার করে বিবেচনা করেছি, তবে আমি যা অর্জন করতে চাইছি তার পুনরাবৃত্ত প্রকৃতির কারণে, আমি এটি সফলভাবে করার জন্য কোনও উপায় খুঁজে পাইনি (এমনকি ConcurrentBag) - তবে আমি ভুল প্রমাণিত হতে পেরে আনন্দিত :)

উপসংহার

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

আমি ঠিক কী দিয়ে আমি বেঞ্চমার্ক করার চেষ্টা করছিলাম তা চেষ্টা করতে StopWatchচাইলে প্রতিটি লুপের 4 টি পর্যন্ত 13 টি লুপ গণনা করুন - যা তালিকায় প্রায় 67 মিটার + লাইন তৈরি করে। আমার মেশিনে (i5-3320M 2.6GHz) অপটিমাইজড সংস্করণটি করতে প্রায় 2.2 সেকেন্ড লাগে।


4
লিনাক ব্যবহার করার চেষ্টা করুন এবং আপনি যদি মাল্টিকোর প্রসেসর ব্যবহার করছেন তবে সমান্তরাল.ফর
জলপেশ ভাদগামা

4
আমি যা দেখছি তার উপর ভিত্তি করে এই অনুমতিগুলি নয় তবে খুব কয়েকটি ছোট (2-4 উপাদান) সেটগুলির সংমিশ্রণগুলি কি এটি সঠিক বা আপনি কি একটি সেটের সমস্ত / কিছু অনুমতি চান ?
কার্স্টেন

আমি ধরে নিয়েছি আপনি ইতিমধ্যে অনুসন্ধান করেছেন bing.com/search?q=c%23+ কম্পন ++ গুণমান ইতিমধ্যে এবং কোনও কারণে (পোস্টে উল্লেখ করা হয়নি) বিদ্যমান উত্তরগুলির বিরুদ্ধে সিদ্ধান্ত নিয়েছে স্ট্যাকওভারফ্লো / সেকশনস / 4319049/ … ... তালিকা বিবেচনা করুন আপনি যে বিকল্পগুলি দেখেছেন এবং এই প্রশ্নটিকে আরও ভাল করার পক্ষে সিদ্ধান্ত নিয়েছেন।
আলেক্সি লেভেনকভ

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

4
@ পেজ: আপনার সামনের সমন্বয় আপ-ফ্রন্ট কেন করা দরকার? যখন আপনার প্রয়োজন হবে তখন কেন এটির সূচী থেকে কোনও সংমিশ্রণ তৈরি করবেন না?
পিটার উইটভয়েট

উত্তর:


61

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

আপনি একটি কাঠামোর বৈশিষ্ট্যগুলি ব্যবহার করতে পারেন এবং কাঠামোটি আগেই বরাদ্দ করতে পারেন। আমি নীচের নমুনায় কিছু স্তর কেটেছি, তবে আমি নিশ্চিত যে আপনি নির্দিষ্টকরণগুলি বের করতে সক্ষম হবেন। আসল (রিলিজ মোড) এর চেয়ে প্রায় 5-6 গুণ দ্রুত গতিতে চলে।

বাধা:

struct ByteBlock
{
    public byte A;
    public byte B;
    public byte C;
    public byte D;
    public byte E;
}

লুপ:

var data = new ByteBlock[2*3*4*3*4];
var counter = 0;

var bytes = new ByteBlock();

for (byte a = 0; a < 2; a++)
{
    bytes.A = a;
    for (byte b = 0; b < 3; b++)
    {
        bytes.B = b;
        for (byte c = 0; c < 4; c++)
        {
            bytes.C = c;
            for (byte d = 0; d < 3; d++)
            {
                bytes.D = d;
                for (byte e = 0; e < 4; e++)
                {
                    bytes.E = e;
                    data[counter++] = bytes;
                }
            }
        }
    }
}

এটি দ্রুততর কারণ এটি প্রতিবার তালিকায় যুক্ত করে কোনও নতুন তালিকা বরাদ্দ করে না। এছাড়াও যেহেতু এটি এই তালিকাটি তৈরি করছে, এর জন্য প্রতিটি অন্যান্য মান (a, b, c, d, e) এর একটি রেফারেন্স প্রয়োজন। আপনি ধরে নিতে পারেন প্রতিটি মান লুপের ভিতরে একবারই সংশোধিত হয়, তাই আমরা এটি (ডেটা লোকালটি) করতে এটি অনুকূল করতে পারি।

পার্শ্ব প্রতিক্রিয়া জন্য মন্তব্য পড়ুন।

এর T[]পরিবর্তে একটি ব্যবহারের জন্য উত্তরটি সম্পাদনা করে List<T>


4
এটি একটি কাঠামো, যাতে আপনার ঠিক হওয়া উচিত =) এগুলি সবই অনন্য। List<T>.Addপদ্ধতিটি কল করার সময় এটি অনুলিপি করা হয় ।
ক্যারিমিরিল

4
আপনি যদি
এরিক

4
থেকে সাবধান Stackoverflow ব্যতিক্রম যখন স্ট্যাক অনেকগুলি অবজেক্ট বণ্টন।
Andrei Tătar

7
@ অ্যান্ড্রু আমি আপনার বক্তব্যটি পাই না। এই কোডটি পুনরাবৃত্তিযোগ্য নয় এবং এর ন্যূনতম স্ট্যাক ব্যবহার রয়েছে।
কোডসইনচাউস

4
@ অ্যান্ড্রু: স্ট্যাকওভারফ্লো নয়, স্মৃতিশক্তি শেষ নয়। এটি কারণ List<T>.Add()এটি কী স্টোর করতে পারে তার বিন্দু ছাড়িয়ে যায়। এটি এটির আকার পরিবর্তন করবে (আকারে দ্বিগুণ), যা মেমরির 2 গিগাবাইটের বেশি হয়ে যায়। নতুন তালিকা <বাইটব্লক> (ম্যাক্স্পারলিভেল.অগ্রিগ্রেট (1, (x, y) => x * y)) ব্যবহার করে প্রাকপলোকটি করার চেষ্টা করুন, যদিও এর ইতিমধ্যে 'এলোমেলো' যে আপনাকে স্মৃতিতে এই ডেটার একটি সম্পূর্ণ 2 জিবি ব্লক প্রয়োজন block এছাড়াও সেই তথ্যটি নোট করুন o টোআররে (); ব্যয়বহুল কারণ এটি আইটেমগুলিকে স্মৃতিতে দুই বার রাখে। [
পুনঃপ্রকাশিত

33

আপনি যা করছেন তা গণনা করা হচ্ছে (ভেরিয়েবল রেডিক্স সহ, তবে এখনও গণনা করা হচ্ছে)।

যেহেতু আপনি সি # ব্যবহার করছেন, আমি ধরে নিয়েছি আপনি দরকারী মেমরি লেআউট এবং ডেটা স্ট্রাকচারের সাথে খেলতে চান না যা আপনাকে সত্যই আপনার কোডটি অনুকূলিত করতে দেয়।

সুতরাং এখানে আমি আলাদা কিছু পোস্ট করছি, এটি আপনার ক্ষেত্রে উপযুক্ত নাও হতে পারে তবে এটি লক্ষণীয় actually যদি আপনি প্রকৃতপক্ষে একটি বিরাট ফ্যাশনে তালিকাটি অ্যাক্সেস করেন তবে এখানে এমন একটি শ্রেণি রয়েছে যা আপনাকে রৈখিক সময়ের মধ্যে আই-তম উপাদানটি গণনা করতে দেয় (পরিবর্তে) অন্যান্য উত্তর হিসাবে ক্ষতিকারক চেয়ে)

class Counter
{
    public int[] Radices;

    public int[] this[int n]
    {
        get 
        { 
            int[] v = new int[Radices.Length];
            int i = Radices.Length - 1;

            while (n != 0 && i >= 0)
            {
                //Hope C# has an IL-opcode for div-and-reminder like x86 do
                v[i] = n % Radices[i];
                n /= Radices[i--];
            }
            return v;
        }
    }
}

আপনি এই শ্রেণিটি এভাবে ব্যবহার করতে পারেন

Counter c = new Counter();
c.Radices = new int[] { 2,3,4,3,4,3,3,4,2,4,4,3,4};

এখন c[i]আপনার তালিকা হিসাবে একই, এটির নাম l, l[i]

যেমন আপনি দেখতে পাচ্ছেন, আপনি সহজেই এই সমস্ত লুপগুলি এড়াতে পারবেন :) এমনকি আপনি যখন সমস্ত তালিকা নিখুঁতভাবে গণনা করেন তখনই আপনি কেবল একটি ক্যারি-রিপল কাউন্টার বাস্তবায়ন করতে পারেন।

কাউন্টারগুলি একটি খুব অধ্যয়নযোগ্য বিষয়, যদি আপনি মনে করেন তবে কিছু সাহিত্যের সন্ধানের জন্য দৃ strongly় পরামর্শ দিচ্ছি।


4
আমি আপনার উত্তরটি পছন্দ করি, তবে অন্য সমস্ত উত্তর ঘনিষ্ঠভাবে বলা অসত্য।
বিস্কুট

4
ক্যারামিরিলের উত্তরের তুলনায় এর গতি কী?
জন ওডো

17
"সি-কিডি- #", সত্যিই? এটি সম্পূর্ণরূপে অপ্রয়োজনীয় বলে মনে হচ্ছে।
কেচালাক্স


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

14

পদ্ধতি 1

এটিকে দ্রুত করার একটি উপায় হ'ল আপনি যদি এর List<byte[]>মতো ব্যবহারের পরিকল্পনা করে থাকেন তবে সক্ষমতা উল্লেখ করা ।

var data = new List<byte[]>(2 * 3 * 4 * 3 * 4 * 3 * 3 * 4 * 2 * 4 * 4 * 3 * 4);

পদ্ধতি 2

তদ্ব্যতীত, আপনি System.Arrayদ্রুত অ্যাক্সেস পেতে সরাসরি ব্যবহার করতে পারেন । আমি এই পদ্ধতির প্রস্তাব দিচ্ছি যদি আপনার প্রশ্নটি জোর দেয় যে প্রতিটি উপাদান শারীরিকভাবে মেমরির মধ্যে রয়েছে, সামনে।

var data = new byte[2 * 3 * 4 * 3 * 4 * 3 * 3 * 4 * 2 * 4 * 4 * 3 * 4][];
int counter = 0;

for (byte a = 0; a < 2; a++)
    for (byte b = 0; b < 3; b++)
        for (byte c = 0; c < 4; c++)
            for (byte d = 0; d < 3; d++)
                for (byte e = 0; e < 4; e++)
                    for (byte f = 0; f < 3; f++)
                        for (byte g = 0; g < 3; g++)
                            for (byte h = 0; h < 4; h++)
                                for (byte i = 0; i < 2; i++)
                                    for (byte j = 0; j < 4; j++)
                                        for (byte k = 0; k < 4; k++)
                                            for (byte l = 0; l < 3; l++)
                                                for (byte m = 0; m < 4; m++)
                                                    data[counter++] = new[] { a, b, c, d, e, f, g, h, i, j, k, l, m };

এটি আমার কম্পিউটারে সম্পূর্ণ হতে 596 এমএস লাগবে , যা প্রশ্নযুক্ত কোডের চেয়ে প্রায় 10.4% দ্রুত (যা 658 মিমি লাগে)।

পদ্ধতি 3

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

এই বাস্তবায়নে প্রতিটি উপাদান অ্যাক্সেসের পরে অলসভাবে, ফ্লাইটে নির্ধারিত হয়। স্বাভাবিকভাবেই, এটি অতিরিক্ত সিপিইউয়ের দামে আসে যা অ্যাক্সেসের সময় ব্যয় করা হয়।

class HypotheticalBytes
{
    private readonly int _c1, _c2, _c3, _c4, _c5, _c6, _c7, _c8, _c9, _c10, _c11, _c12;
    private readonly int _t0, _t1, _t2, _t3, _t4, _t5, _t6, _t7, _t8, _t9, _t10, _t11;

    public int Count
    {
        get { return _t0; }
    }

    public HypotheticalBytes(
        int c0, int c1, int c2, int c3, int c4, int c5, int c6, int c7, int c8, int c9, int c10, int c11, int c12)
    {
        _c1 = c1;
        _c2 = c2;
        _c3 = c3;
        _c4 = c4;
        _c5 = c5;
        _c6 = c6;
        _c7 = c7;
        _c8 = c8;
        _c9 = c9;
        _c10 = c10;
        _c11 = c11;
        _c12 = c12;
        _t11 = _c12 * c11;
        _t10 = _t11 * c10;
        _t9 = _t10 * c9;
        _t8 = _t9 * c8;
        _t7 = _t8 * c7;
        _t6 = _t7 * c6;
        _t5 = _t6 * c5;
        _t4 = _t5 * c4;
        _t3 = _t4 * c3;
        _t2 = _t3 * c2;
        _t1 = _t2 * c1;
        _t0 = _t1 * c0;
    }

    public byte[] this[int index]
    {
        get
        {
            return new[]
            {
                (byte)(index / _t1),
                (byte)((index / _t2) % _c1),
                (byte)((index / _t3) % _c2),
                (byte)((index / _t4) % _c3),
                (byte)((index / _t5) % _c4),
                (byte)((index / _t6) % _c5),
                (byte)((index / _t7) % _c6),
                (byte)((index / _t8) % _c7),
                (byte)((index / _t9) % _c8),
                (byte)((index / _t10) % _c9),
                (byte)((index / _t11) % _c10),
                (byte)((index / _c12) % _c11),
                (byte)(index % _c12)
            };
        }
    }
}

এটি আমার কম্পিউটারে সম্পূর্ণ 897 এমএস লাগবে ( পদ্ধতি 2Array হিসাবে তৈরি করা ও যুক্ত করাও ), যা প্রশ্নের কোডের তুলনায় প্রায় 36.3% ধীর (যা 658 মিমি লাগে)।


4
আপনার দ্বিতীয় পরামর্শটি মেমরির ব্যবহারের ক্ষেত্রেও একটি গুরুত্বপূর্ণ সাশ্রয়। (তবে আমি নোট করব যে এটি ধরে নিয়েছে যে তালিকাটি পরিবর্তন করা উচিত নয়)
তাইমির

আমার একবারে সম্পূর্ণ তালিকা তৈরি করা দরকার - আমি তালিকার মধ্যে কোনও সূচকটি উল্লেখ করতে পারি না।
বেনপেজ

@ টেইমির ধন্যবাদ আমি সেই অনুযায়ী নোট করতে আপডেট করব। যদি বাস্তবায়নটি সত্যই জোর দেয় যে আপনার কাছে পুরো তালিকাটি সামনে উপস্থিত রয়েছে, তবে এই 3 য় বিকল্পটি অবশ্যই আপনার জন্য কাজ করবে না।
বিস্কুট

4
@ বেনপেজ আপনার তালিকাটি জনবহুল কেন দরকার?
তাইমির

14

আমার মেশিনে, এটি 222 এমএস বনাম 760 এমএস (লুপগুলির জন্য 13) এর সংমিশ্রণগুলি তৈরি করে:

private static byte[,] GenerateCombinations(byte[] maxNumberPerLevel)
{
    var levels = maxNumberPerLevel.Length;

    var periodsPerLevel = new int[levels];
    var totalItems = 1;
    for (var i = 0; i < levels; i++)
    {
        periodsPerLevel[i] = totalItems;
        totalItems *= maxNumberPerLevel[i];
    }

    var results = new byte[totalItems, levels];

    Parallel.For(0, levels, level =>
    {
        var periodPerLevel = periodsPerLevel[level];
        var maxPerLevel = maxNumberPerLevel[level];
        for (var i = 0; i < totalItems; i++)
            results[i, level] = (byte)(i / periodPerLevel % maxPerLevel);
    });

    return results;
}

এটি একটি দুর্দান্ত উত্তর! দুর্ভাগ্যক্রমে এটি নেস্টেড লুপগুলির চেয়ে ধীর গতিতে চলে। টিপিএল ব্যবহার করে আপনি যে কোনও সুযোগ সম্পাদনা করতে পারবেন?
বেনপেজ

দুর্ভাগ্যক্রমে এখনও কিছুটা ধীর গতির।
বেনপেজ

4
@ বেনপেজ এটি কমপক্ষে ২ বার দ্রুততর করার সহজ উপায় আছে। আপনাকে কেবল ফলাফলের ধরণটি ইনট [,] এ পরিবর্তন করতে হবে। এটি একটি কলে পুরো অ্যারে মেমরি বরাদ্দ করবে। আমি নিশ্চিত না যে এটি আপনার প্রয়োজনের সাথে কীভাবে ফিট করে (রিটার্নের ধরণ পরিবর্তন করে)।
Andrei Tătar

8
var numbers = new[] { 2, 3, 4, 3, 4, 3, 3, 4, 2, 4, 4, 3, 4 };
var result = (numbers.Select(i => Enumerable.Range(0, i))).CartesianProduct();

Http://ericlippert.com/2010/06/28/computing-a-cartesian-product-with-linq/ এ এক্সটেনশন পদ্ধতিটি ব্যবহার করে

public static IEnumerable<IEnumerable<T>> CartesianProduct<T>(this IEnumerable<IEnumerable<T>> sequences)
{
    // base case: 
    IEnumerable<IEnumerable<T>> result =
        new[] { Enumerable.Empty<T>() };
    foreach (var sequence in sequences)
    {
        // don't close over the loop variable (fixed in C# 5 BTW)
        var s = sequence;
        // recursive case: use SelectMany to build 
        // the new product out of the old one 
        result =
            from seq in result
            from item in s
            select seq.Concat(new[] { item });
    }
    return result;
}

4
এটি অনেক ধীর গতিতে
চলেছে

8

তালিকার অভ্যন্তরীণভাবে একটি অ্যারে থাকে যেখানে এটি একটি নির্দিষ্ট দৈর্ঘ্যের সাথে মানগুলি সংরক্ষণ করে। আপনি যখন তালিকায় কল করবেন enough পর্যাপ্ত জায়গা আছে কিনা তা পরীক্ষা করে দেখুন। এটি যখন নতুন উপাদান যুক্ত করতে না পারে এটি বৃহত্তর আকারের একটি নতুন অ্যারে তৈরি করবে, পূর্ববর্তী সমস্ত উপাদানগুলি অনুলিপি করুন, তারপরে নতুনটি যুক্ত করুন। এটি বেশ কয়েকটি চক্র নেয়।

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

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


আমি আসলে একটি নিয়মিত অ্যারে প্রাক-বরাদ্দ করার চেষ্টা করেছি এবং এটি বিশ্বাস করি বা না, এটি ধীর। আমি উপরে যেমন বলেছি, এটি অন ফ্লাইটে তৈরি করা দরকার, আমি একবার এটি গণনা করতে এবং ছেড়ে দিতে পারি না।
বেনপেজ

সত্যি? বাহ - আপনি সঠিকভাবে সক্ষম অপ্টিমাইজেশন দিয়ে চলছে? (কেবল জিজ্ঞাসা করা)
কার্স্টেন

আহ এটি অন্য সমস্যা, নিয়মিত অ্যারে [x, y] ব্যবহার করা ভাল তবে অ্যারের অ্যারে দ্রুত হবে be stackoverflow.com/questions/597720/... কারণ কিভাবে তারা বিশ্বের সেরা ফণা অধীন implemeted করছি
gjvdkamp

5

এখানে একটি পৃথক পদ্ধতিতে কেবল 2 টি লুপের প্রয়োজন। ধারণাটি হ'ল প্রথম উপাদানটি বাড়ানো এবং যদি সেই সংখ্যাটি পরেরটি বাড়ানোর চেয়ে বেশি হয়।

ডেটা প্রদর্শন করার পরিবর্তে, আপনি বর্তমানভ্যালুগুলি ব্যবহার করতে পারেন lক্লোন এবং ক্লোন করা সংস্করণটি আপনার তালিকায় যুক্ত করতে পারেন। আমার জন্য এটি আপনার সংস্করণের চেয়ে দ্রুত দৌড়েছিল।

byte[] maxValues = {2, 3, 4};
byte[] currentValues = {0, 0, 0};

do {
    Console.WriteLine("{0}, {1}, {2}", currentValues[0], currentValues[1], currentValues[2]);

    currentValues[0] += 1;

    for (int i = 0; i <= maxValues.Count - 2; i++) {
        if (currentValues[i] < maxValues[i]) {
            break;
        }

        currentValues[i] = 0;
        currentValues[i + 1] += 1;
    }

// Stop the whole thing if the last number is over
// } while (currentValues[currentValues.Length-1] < maxValues[maxValues.Length-1]);
} while (currentValues.Last() < maxValues.Last());
  • আশা করি এই কোডটি কার্যকর হয়, আমি এটি ভিবি থেকে রূপান্তর করেছি

3

আপনার সমস্ত নম্বর সংকলন সময় ধ্রুবক।

একটি তালিকাতে সমস্ত লুপগুলি তালিকাভুক্ত করার বিষয়ে কী (কোড লেখার জন্য আপনার প্রোগ্রামটি ব্যবহার করে):

data.Add(new [] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0});
data.Add(new [] {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0});
etc.

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

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


সিরিয়ালাইজেশন বক্স পদ্ধতির বাইরে সত্যই একটি দুর্দান্ত চিন্তাভাবনা!
জোয়েল বি

দুর্ভাগ্যক্রমে তালিকার সর্বোচ্চটি গতিশীল, আমি স্থিতিস্থলে এটি টাইপ করতে পারি না। ভাল ধারণা যদিও!
বেনপেজ

2

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

নীচের পদ্ধতিরটি আরও দ্রুত (আমার বাক্সে আসলটির জন্য 41ms বনাম 1071ms):

struct element {
    public byte a;
    public byte b;
    public byte c;
    public byte d;
    public byte e;
    public byte f;
    public byte g;
    public byte h;
    public byte i;
    public byte j;
    public byte k;
    public byte l;
    public byte m;
}

element[] WithStruct() {
    var t = new element[3981312];
    int z = 0;
    for (byte a = 0; a < 2; a++)
    for (byte b = 0; b < 3; b++)
    for (byte c = 0; c < 4; c++)
    for (byte d = 0; d < 3; d++)
    for (byte e = 0; e < 4; e++)
    for (byte f = 0; f < 3; f++)
    for (byte g = 0; g < 3; g++)
    for (byte h = 0; h < 4; h++)
    for (byte i = 0; i < 2; i++)
    for (byte j = 0; j < 4; j++)
    for (byte k = 0; k < 4; k++)
    for (byte l = 0; l < 3; l++)
    for (byte m = 0; m < 4; m++)
    {
        t[z].a = a;
        t[z].b = b;
        t[z].c = c;
        t[z].d = d;
        t[z].e = e;
        t[z].f = f;
        t[z].g = g;
        t[z].h = h;
        t[z].i = i;
        t[z].j = j;
        t[z].k = k;
        t[z].l = l;
        t[z].m = m;
        z++;
    }
    return t;
}

ভাল ধারণা - বাস্তবে, আমি আমার বাস্তব-বিশ্ব প্রকল্পে এটিই করেছি - সরলতার কারণে আমি কেবল এটি মূল সমাধানে রাখিনি। আমি সাধারণত নেস্টেড লুপগুলির জন্য আরও ভাল বিকল্পের সন্ধান করছিলাম।
বেনপেজ

1

Parallel.For()এটি চালানোর জন্য ব্যবহার সম্পর্কে কী ? ( @ ক্যারামিরিলে অপ্টিমাইজেশন কুডোস গঠন করুন ) আমি মানগুলিতে কিছুটা পরিবর্তন করেছি (2 এর পরিবর্তে 5 হ'ল) ​​সুতরাং ফলাফলগুলিতে আমি আরও আত্মবিশ্বাসী।

    var data = new ConcurrentStack<List<Bytes>>();
    var sw = new Stopwatch();

    sw.Start();

    Parallel.For(0, 5, () => new List<Bytes>(3*4*3*4*3*3*4*2*4*4*3*4),
      (a, loop, localList) => {
        var bytes = new Bytes();
        bytes.A = (byte) a;
        for (byte b = 0; b < 3; b++) {
          bytes.B = b;
          for (byte c = 0; c < 4; c++) {
            bytes.C = c; 
            for (byte d = 0; d < 3; d++) {
              bytes.D = d; 
              for (byte e = 0; e < 4; e++) {
                bytes.E = e; 
                for (byte f = 0; f < 3; f++) {
                  bytes.F = f; 
                  for (byte g = 0; g < 3; g++) {
                    bytes.G = g; 
                    for (byte h = 0; h < 4; h++) {
                      bytes.H = h; 
                      for (byte i = 0; i < 2; i++) {
                        bytes.I = i; 
                        for (byte j = 0; j < 4; j++) {
                          bytes.J = j; 
                          for (byte k = 0; k < 4; k++) {
                            bytes.K = k; 
                            for (byte l = 0; l < 3; l++) {
                              bytes.L = l;
                              for (byte m = 0; m < 4; m++) {
                                bytes.M = m;
                                localList.Add(bytes);
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }


        return localList;
      }, x => {
        data.Push(x);
    });

    var joinedData = _join(data);

_join() এটি একটি ব্যক্তিগত পদ্ধতি, এটি হিসাবে সংজ্ঞায়িত:

private static IList<Bytes> _join(IEnumerable<IList<Bytes>> data) {
  var value = new List<Bytes>();
  foreach (var d in data) {
    value.AddRange(d);
  }
  return value;
}

আমার সিস্টেমে, এই সংস্করণটি প্রায় 6 গুণ দ্রুত (0.27 সেকেন্ডের তুলনায় 1.718 সেকেন্ড) দ্রুত চলে।


4
এটি আপনাকে মিথ্যা ভাগ করে নেওয়ার পক্ষে যথেষ্ট গ্যারান্টিযুক্ত এবং সম্ভবত বহুগুণ ধীর হয়ে যাবে।
gjvdkamp

খারাপ নয় - দুর্ভাগ্যক্রমে এটি লুপগুলির চেয়ে ধীর গতিতে চলে । এফডব্লিউআইডাব্লু আমি এটি সমস্ত ভাইস Parallel.Forএবং ভিএস ক্র্যাশ করে দিয়ে চেষ্টা করেছি !
বেনপেজ

@gjvdkamp আমি আমার উত্তরটিকে একটি সমান্তরাল সংস্করণ দিয়ে আপডেট করেছি যা আমার বিশ্বাস যে মিথ্যা ভাগ করে নেওয়ার সমস্যাটি দূর করে।
jdphenix

0

আপনার কয়েকটি নম্বর বিটসের পূর্ণসংখ্যার সংখ্যায় পুরোপুরি ফিট করে, তাই আপনি তাদের উপরের স্তরের নম্বর দিয়ে "প্যাক" করতে পারেন:

for (byte lm = 0; lm < 12; lm++)
{
    ...
    t[z].l = (lm&12)>>2;
    t[z].m = lm&3;
    ...
}

অবশ্যই, এটি কোডটি কম পঠনযোগ্য করে তোলে তবে আপনি একটি লুপ সংরক্ষণ করেছেন। এটি প্রতিবার সংখ্যার একটিতে দু'জনের শক্তি হ'ল এটি করা যেতে পারে যা আপনার ক্ষেত্রে সাতবার।


আমি এই উত্তর সম্পর্কে আরও জানতে চাই - আপনি কি এটিতে প্রসারিত করতে পারেন?
বেনপেজ

দেরিতে উত্তরের জন্য দুঃখিত. মিঃ 0 থেকে 3 পর্যন্ত চলে যায়, যা বাইনারিতে 0 থেকে 2, l থেকে 0 থেকে 2 তৈরি করে, যা 00 থেকে 10 করে, তাই আপনি যদি এগুলি আলাদাভাবে মুদ্রণ করেন তবে এটি তৈরি করবে: 00 00 00 01 01 00 10 11 11 01 00 .. 10 11 আপনি এগুলি একসাথে 4 বিটের একত্রে মিশ্রিত করতে পারেন, 0000 থেকে 1011 পর্যন্ত গিয়ে একটি মাস্ক এলএম ব্যবহার করে উপযুক্ত বিটগুলি নির্বাচন করতে পারেন এবং 3 টি দ্বৈত এবং lm এবং (11) বি lm এর মধ্যে তৈরি করে এবং 12 টি একইভাবে এলএম দিয়ে তৈরি করে এবং (1100) বি এর পরে আমরা "আসল" নম্বর পেতে দুটি বিট দ্বারা স্থানান্তরিত করব। যাইহোক, ঠিক বুঝতে পেরেছি এই ক্ষেত্রে lm >> 2 করা যথেষ্ট।
ফ্যাবিয়েন ডুপোন্ট

0

এখানে আরও একটি সমাধান দেওয়া হল। ভিএস এর বাইরে এটি 437.5 এমএস হিসাবে দ্রুত চলে যা মূল কোডের চেয়ে 26% দ্রুত (আমার কম্পিউটারে 593.7):

static List<byte[]> Combinations(byte[] maxs)
{
  int length = maxs.Length;
  int count = 1; // 3981312;
  Array.ForEach(maxs, m => count *= m);
  byte[][] data = new byte[count][];
  byte[] counters = new byte[length];

  for (int r = 0; r < count; r++)
  {
    byte[] row = new byte[length];
    for (int c = 0; c < length; c++)
      row[c] = counters[c];
    data[r] = row;

    for (int i = length - 1; i >= 0; i--)
    {
      counters[i]++;
      if (counters[i] == maxs[i])
        counters[i] = 0;
      else
        break;
    }
  }

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