C# break, continue & నెస్టెడ్ లూప్స్ (Loop Performance)
స్వాగతం అధ్యాయం 08 కి! 🛑 లూప్ నియంత్రణ & హై-పెర్ఫార్మెన్స్ అల్గారిథమ్స్
గత అధ్యాయంలో లూప్స్ ఎలా మొదలవుతాయి మరియు ఎలా తిరుగుతాయో నేర్చుకున్నాం. కానీ ఒక సాఫ్ట్వేర్ ఇంజనీర్గా మీకు లూప్ను కేవలం తిప్పడం మాత్రమే కాదు — దాన్ని ఎప్పుడు ఆపాలి (break), ఎప్పుడు నిర్దిష్ట రౌండ్ను దాటవేయాలి (continue), మరియు నెస్టెడ్ లూప్స్లో సిస్టమ్ స్లో కాకుండా ఎలా నిరోధించాలి అనే కమాండ్ ఉండాలి!
ఉదాహరణకు: 10 లక్షల మంది యూజర్ల డేటాబేస్లో ఒక నిర్దిష్ట యూజర్ కోసం వెతుకుతున్నారు. 5వ రికార్డు వద్దే ఆ యూజర్ దొరికితే — మిగిలిన 9,99,995 రికార్డులను కూడా అనవసరంగా లూప్ తిప్పడం తీవ్రమైన రిసోర్స్ వేస్ట్! అలాగే చెల్లని లేదా కరప్ట్ అయిన డేటా ఎదురైనప్పుడు ఆ ఒక్క ఐటెమ్ను స్కిప్ చేసి తదుపరి ఐటెమ్కు వెళ్లడం అత్యవసరం.
ఈ సమగ్ర 8వ అధ్యాయంతో మనం Phase 02 (కంట్రోల్ ఫ్లో & లూప్స్) ను ఘనంగా ముగిస్తూ — break, continue, నెస్టెడ్ లూప్స్, (O(N^2)) టైమ్ కాంప్లెక్సిటీ ప్రమాదాలు, మరియు మల్టీ-లెవల్ లూప్ బ్రేకింగ్ స్ట్రాటజీలను లోతుగా నేర్చుకొని — ఒక రియల్-వరల్డ్ ఫిన్టెక్ ఫ్రాడ్ & డూప్లికేట్ ట్రాన్సాక్షన్ డిటెక్షన్ ఇంజిన్ను నిర్మిస్తాం!
1 🛑 లూప్ నియంత్రణ స్టేట్మెంట్స్: break మరియు continue
లూప్ సాధారణంగా తన కండిషన్ false అయ్యే వరకు సహజంగా తిరుగుతుంది. కానీ రన్టైమ్లో పరిస్థితులు మారినప్పుడు మనం లూప్ యొక్క సహజ ప్రవాహాన్ని మార్చడానికి రెండు కీవర్డ్స్ ఉపయోగిస్తాం:
break(తక్షణ నిష్క్రమణ): లూప్ను అక్కడికక్కడే శాశ్వతంగా రద్దు చేసి, లూప్ వెలుపల ఉన్న తర్వాతి లైన్కు కంట్రోల్ను బదిలీ చేస్తుంది.continue(ప్రస్తుత రౌండ్ దాటవేత): ప్రస్తుత ఇటరేషన్లోని మిగిలిన కోడ్ను వదిలేసి, నేరుగా తదుపరి రౌండ్ (Next Iteration) కు దూకుతుంది.
2 ⚡ break స్టేట్మెంట్ — ఎర్లీ సెర్చ్ టెర్మినేషన్ & ఆప్టిమైజేషన్
ఒక వస్తువు దొరికిన వెంటనే లూప్ను ఆపివేయడం (Short-Circuit Search) వల్ల CPU వృధా కాకుండా బిలియన్ల సైకిల్స్ ఆదా అవుతాయి:
string[] customers = { "రమేష్", "సురేష్", "కళ్యాణ్", "దివ్య", "మహేష్", "స్నేహ" };
string target = "కళ్యాణ్";
int searchSteps = 0;
for (int i = 0; i < customers.Length; i++)
{
searchSteps++;
if (customers[i] == target)
{
Console.WriteLine($"🎉 {target} ఇండెక్స్ {i} వద్ద లభించారు!");
break; // కస్టమర్ దొరికారు, మిగిలిన అర్రేను వెతకడం ఆపివేయి!
}
}
Console.WriteLine($"మొత్తం వెతికిన దశలు: {searchSteps} (అర్రే సైజు {customers.Length} అయినప్పటికీ)");
break లేకపోతే లూప్ అనవసరంగా చివరి వరకు తిరుగుతుంది. లక్షల సంఖ్యలో డేటా ఉన్నప్పుడు ఇది సాఫ్ట్వేర్ను విపరీతంగా మందగింపజేస్తుంది.
3 ⏭️ continue స్టేట్మెంట్ — చెల్లని డేటాను స్కిప్ చేయడం
డేటా ప్రాసెస్ చేస్తున్నప్పుడు కొన్ని అవాంఛనీయ విలువలు (ఉదాహరణకు సున్నా, నెగటివ్ నంబర్లు, కరప్ట్ రికార్డులు) వచ్చినప్పుడు — లూప్ను ఆపకుండా, కేవలం ఆ ఒక్క బ్యాడ్ రికార్డును స్కిప్ చేయడానికి continue ఉపయోగిస్తారు.
int[] rawSensorReadings = { 25, -999, 28, 0, 31, -999, 29 };
int processedCount = 0;
int sum = 0;
foreach (int reading in rawSensorReadings)
{
// సెన్సార్ ఎర్రర్ కోడ్ -999 లేదా 0 అయితే స్కిప్ చేయి
if (reading == -999 || reading == 0)
{
Console.WriteLine($"⚠️ చెల్లని రీడింగ్ ({reading}) దాటవేయబడింది.");
continue; // క్రింది భాగం రన్ కాదు, నెక్స్ట్ రీడింగ్ కు వెళ్తుంది
}
sum += reading;
processedCount++;
Console.WriteLine($"సరైన రీడింగ్ నమోదు: {reading}°C");
}
Console.WriteLine($"\nవిజయవంతంగా ప్రాసెస్ చేసిన రీడింగ్స్: {processedCount}, సగటు: {(double)sum / processedCount:F1}°C");
4 🪺 నెస్టెడ్ లూప్స్ (Nested Loops: Grids & Matrices)
ఒక లూప్ లోపల మరొక లూప్ ఉండటాన్ని నెస్టెడ్ లూప్ (Nested Loop) అంటారు. బయటి లూప్ (Outer Loop) ఒక్కసారి తిరిగితే, లోపలి లూప్ (Inner Loop) తన పూర్తి సైకిల్ను పూర్తి చేస్తుంది.
2D గ్రిడ్స్, చెస్ బోర్డులు, పిక్సెల్ మ్యాట్రిక్స్, మరియు రో-కాలమ్ టేబుల్స్ ప్రాసెస్ చేయడానికి నెస్టెడ్ లూప్స్ ఉపయోగిస్తారు:
Console.WriteLine("--- 1 నుండి 5 వరకు గుణకార పట్టిక గ్రిడ్ ---\n");
// బయటి లూప్: అడ్డు వరుసలు (Rows)
for (int row = 1; row <= 5; row++)
{
// లోపలి లూప్: నిలువు వరుసలు (Columns)
for (int col = 1; col <= 5; col++)
{
Console.Write($"{row * col,4}"); // 4 స్పేసెస్ తో ఫార్మాటింగ్
}
Console.WriteLine(); // ప్రతి రో పూర్తయిన తర్వాత కొత్త లైన్
}
5 ⏳ టైమ్ కాంప్లెక్సిటీ అనలిసిస్: O(N) vs O(N²) ప్రమాదాలు
సాఫ్ట్వేర్ ఇంజనీరింగ్లో నెస్టెడ్ లూప్స్ అత్యంత జాగ్రత్తగా వాడాల్సిన సాధనం.
- ఒకే లూప్ (Single Loop): (O(N)) లీనియర్ టైమ్. 10,000 ఐటెమ్స్ ఉంటే 10,000 ఆపరేషన్స్ (మైక్రోసెకన్లు).
- రెండు నెస్టెడ్ లూప్స్ (Double Nested): (O(N^2)) క్వాడ్రాటిక్ టైమ్. 10,000 ఐటెమ్స్ ఉంటే (10,000 imes 10,000 = mathbf{100,000,000}) (10 కోట్ల ఆపరేషన్స్ - కొన్ని సెకన్లు).
- మూడు నెస్టెడ్ లూప్స్ (Triple Nested): (O(N^3)) క్యూబిక్ టైమ్. సర్వర్ పూర్తిగా ఫ్రీజ్ అయిపోతుంది!
రెండు కలెక్షన్లలో డూప్లికేట్స్ వెతకడానికి రెండు నెస్టెడ్ లూప్స్ ((O(N^2))) రాయడానికి బదులు — HashSet<T> లేదా Dictionary<K,V> వాడితే అదే పని (O(N)) లో పూర్తవుతుంది!
6 🎯 మల్టీ-లెవల్ లూప్ బ్రేకింగ్ (Breaking Outer Loops in C#)
C# లో ఒక నెస్టెడ్ లూప్ లోపల break; రాస్తే — అది కేవలం లోపలి లూప్ను మాత్రమే రద్దు చేస్తుంది, బయటి లూప్ అలాగే నడుస్తూనే ఉంటుంది!
జావాలో లేబుల్డ్ బ్రేక్స్ (break outerLoop;) ఉంటాయి, కానీ C# లో అవి లేవు. C# లో మొత్తం అన్ని నెస్టెడ్ లూప్స్ నుండి ఒకేసారి బయటపడటానికి 3 ప్రొఫెషనల్ విధానాలు ఉన్నాయి:
విధానం 1: బూలియన్ ఫ్లాగ్ (Clean Standard)
bool itemFound = false;
for (int r = 0; r < 10 && !itemFound; r++)
{
for (int c = 0; c < 10; c++)
{
if (r == 3 && c == 7)
{
Console.WriteLine($"లక్ష్యం దొరికింది ({r}, {c}) వద్ద!");
itemFound = true;
break; // లోపలి లూప్ బ్రేక్
}
}
}
విధానం 2: మెథడ్ ఎక్స్ట్రాక్షన్ & return (Architect-Preferred)
నెస్టెడ్ లూప్ను ఒక ప్రత్యేక ఫంక్షన్గా రాసి, లక్ష్యం నెరవేరగానే నేరుగా return చేయడం అత్యంత పరిశుభ్రమైన పద్ధతి.
విధానం 3: goto లేబుల్ (The Valid Exception)
సాధారణంగా goto వాడటం మంచిది కాదు, కానీ బహుళ నెస్టెడ్ లూప్స్ నుండి తక్షణమే బయటకు రావడానికి C# లో goto ExitPoint; వాడటం అధికారికంగా ఆమోదించబడిన ఏకైక సందర్భం!
7 🚀 లూప్ ఆప్టిమైజేషన్: Loop Invariant Code Motion
లూప్ ప్రతి రౌండ్లోనూ మారకుండా స్థిరంగా ఉండే కాలిక్యులేషన్స్ను లూప్ లోపల రాయడం పెద్ద తప్పు.
// ❌ చెడ్డ కోడ్: Math.Sqrt() లూప్ లో ప్రతిసారీ మళ్లీ మళ్లీ లెక్కించబడుతుంది
for (int i = 0; i < 10000; i++)
{
double limit = Math.Sqrt(250000.0); // లూప్ లోపల అనవసరం!
// ...
}
// ✅ ఆప్టిమైజ్డ్ కోడ్: స్థిర విలువను లూప్ వెలుపల ఒక్కసారే లెక్కించండి
double precomputedLimit = Math.Sqrt(250000.0);
for (int i = 0; i < 10000; i++)
{
// precomputedLimit వాడండి! CPU క్లాక్ సైకిల్స్ ఆదా అవుతాయి.
}
8 🧵 మల్టీ-కోర్ పార్లలిజం: Parallel.For పరిచయం
ఆధునిక కంప్యూటర్లలో 8 లేదా 16 CPU కోర్లు ఉంటాయి. ఒక సాధారణ for లూప్ కేవలం ఒక్క CPU కోర్పై మాత్రమే రన్ అవుతుంది.
ఒకదానితో ఒకటి సంబంధం లేని లక్షలాది స్వతంత్ర కాలిక్యులేషన్స్ ఉన్నప్పుడు — .NET లోని Parallel.For ద్వారా అన్ని CPU కోర్లను ఏకకాలంలో ఉపయోగించి లూప్ను 10 రెట్లు వేగంగా పూర్తి చేయవచ్చు:
using System.Threading.Tasks;
// అన్ని CPU కోర్లపై సమాంతరంగా లూప్ నడుస్తుంది
Parallel.For(1, 6, i =>
{
Console.WriteLine($"థ్రెడ్ {Environment.CurrentManagedThreadId} రౌండ్ {i} ని ప్రాసెస్ చేస్తోంది.");
});
9 📊 తులనాత్మక పట్టిక: break vs continue vs return vs goto
కంట్రోల్ ఫ్లో జంప్ స్టేట్మెంట్ల పూర్తి తులనాత్మక మ్యాట్రిక్స్:
| కీవర్డ్ | ప్రవర్తన (Action) | పరిధి (Scope) | కాల్ స్టాక్ ప్రభావం | ప్రొఫెషనల్ రికమండేషన్ |
|---|---|---|---|---|
| break | ప్రస్తుత లూప్ను వెంటనే ముగిస్తుంది | తక్షణ లోపలి లూప్ మాత్రమే | లేదు (ఫంక్షన్ లోనే ఉంటుంది) | సెర్చ్ మరియు ఎర్లీ ఎగ్జిట్లకు తప్పనిసరిగా వాడాలి |
| continue | ప్రస్తుత రౌండ్ను వదిలేసి తదుపరి రౌండ్కు వెళ్తుంది | తక్షణ లోపలి లూప్ మాత్రమే | లేదు | చెల్లని డేటాను ఫిల్టర్ చేయడానికి అద్భుతం |
| return | మొత్తం మెథడ్ నుంచే బయటకు వచ్చేస్తుంది | మొత్తం మెథడ్ పరిధి | ఫంక్షన్ స్టాక్ ఫ్రేమ్ పాప్ అవుతుంది | గార్డ్ క్లాజెస్కు, డీప్ నెస్టింగ్ రద్దుకు ఉత్తమం |
| goto | పేర్కొన్న లేబుల్ వద్దకు జంప్ చేస్తుంది | మెథడ్ లోని ఏ లేబుల్ వద్దకైనా | లేదు | బహుళ నెస్టెడ్ లూప్స్ బ్రేకింగ్కు మాత్రమే పరిమితం |
10 🎨 ప్యాటర్న్ ప్రింటింగ్ & మ్యాట్రిక్స్ లాజిక్
ఇంటర్వ్యూలలో నెస్టెడ్ లూప్స్ పై పట్టును పరీక్షించడానికి తరచుగా ప్యాటర్న్ ప్రింటింగ్ అడుగుతారు:
int totalRows = 5;
for (int i = 1; i <= totalRows; i++)
{
// కాలమ్స్ సంఖ్య ప్రస్తుత రో నంబర్ i వరకు మాత్రమే నడుస్తుంది
for (int j = 1; j <= i; j++)
{
Console.Write("* ");
}
Console.WriteLine();
}
11 🚀 రియల్-వరల్డ్ ప్రాజెక్ట్: "Fintech Fraud & Duplicate Transaction Detection Engine"
break, continue, మరియు నెస్టెడ్ లూప్స్ నియంత్రణలతో — ఒక బ్యాంకింగ్ లేదా పేమెంట్ సిస్టమ్లో అనుమానాస్పద డూప్లికేట్ లావాదేవీలను (10 సెకన్ల వ్యవధిలో ఒకే యూజర్ ఒకే మొత్తాన్ని మళ్లీ పంపడం) గుర్తించే ఒక హై-పెర్ఫార్మెన్స్ ఫ్రాడ్ డిటెక్షన్ ఇంజిన్ ను తయారు చేద్దాం!
using System;
Console.OutputEncoding = System.Text.Encoding.UTF8;
Console.WriteLine("=================================================");
Console.WriteLine("🛡️ మన బ్యాంక్ - సెక్యూరిటీ & ఫ్రాడ్ డిటెక్షన్ ఇంజిన్");
Console.WriteLine("=================================================\n");
// నమూనా ట్రాన్సాక్షన్ డేటా రికార్డ్స్
var transactions = new[]
{
new { Id = "TXN101", User = "రాజేష్", Amount = 5000m, Status = "SUCCESS", SecondsAgo = 120 },
new { Id = "TXN102", User = "రాజేష్", Amount = 5000m, Status = "SUCCESS", SecondsAgo = 124 }, // డూప్లికేట్ ఫ్రాడ్! (కేవలం 4 సెకన్ల తేడా)
new { Id = "TXN103", User = "సునీత", Amount = 1200m, Status = "FAILED", SecondsAgo = 90 }, // FAILED (స్కిప్ చేయాలి)
new { Id = "TXN104", User = "విక్రమ్", Amount = 45000m, Status = "SUCCESS", SecondsAgo = 60 },
new { Id = "TXN105", User = "విక్రమ్", Amount = 45000m, Status = "SUCCESS", SecondsAgo = 65 }, // డూప్లికేట్ ఫ్రాడ్!
new { Id = "TXN106", User = "అజయ్", Amount = 250m, Status = "SUCCESS", SecondsAgo = 10 }
};
int totalAudited = 0;
int fraudAlerts = 0;
Console.WriteLine("ఆడిట్ ప్రారంభమైంది... అనుమానాస్పద డూప్లికేట్స్ విశ్లేషణ:\n");
// బయటి లూప్: ప్రతి ట్రాన్సాక్షన్ను తీసుకోవడం
for (int i = 0; i < transactions.Length; i++)
{
var current = transactions[i];
// 'continue' వాడకం: విఫలమైన ట్రాన్సాక్షన్స్ ను నేరుగా స్కిప్ చేయి
if (current.Status == "FAILED")
{
Console.WriteLine($"[INFO] {current.Id} విఫలమైన లావాదేవీ కాబట్టి విశ్లేషణ నుండి దాటవేయబడింది.");
continue;
}
totalAudited++;
// లోపలి లూప్: తర్వాతి లావాదేవీలతో పోల్చడం (Nested Comparison)
for (int j = i + 1; j < transactions.Length; j++)
{
var next = transactions[j];
if (next.Status == "FAILED") continue;
// ఫ్రాడ్ షరతులు: ఒకే యూజర్ + ఒకే మొత్తం + 10 సెకన్ల లోపు జరగడం
bool isSameUser = current.User == next.User;
bool isSameAmount = current.Amount == next.Amount;
int timeDifference = Math.Abs(current.SecondsAgo - next.SecondsAgo);
if (isSameUser && isSameAmount && timeDifference <= 10)
{
fraudAlerts++;
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"🚨 [హెచ్చరిక] ఫ్రాడ్ అనుమానం: {next.Id} అనేది {current.Id} కి డూప్లికేట్!");
Console.WriteLine($" యూజర్: {current.User} | మొత్తం: ₹{current.Amount:N2} | సమయ తేడా: {timeDifference} సెకన్లు!");
Console.ResetColor();
// 'break' వాడకం: ఒకసారి ఫ్రాడ్ దొరికిన తర్వాత మళ్లీ అదే రికార్డును ఇతరులతో పోల్చక్కర్లేదు
break;
}
}
}
// ఆడిట్ సారాంశం
Console.WriteLine("\n=================================================");
Console.WriteLine(" ఆడిట్ నివేదిక సారాంశం ");
Console.WriteLine("=================================================");
Console.WriteLine($"తనిఖీ చేసిన సరైన లావాదేవీలు : {totalAudited}");
Console.WriteLine($"గుర్తించిన అనుమానాస్పద కేసులు : {fraudAlerts}");
Console.WriteLine("భద్రతా చర్యలు: సదరు ఖాతాలపై తక్షణ విచారణకు ఆదేశించాం.");
Console.WriteLine("=================================================\n");
ఈ పూర్తి కోడ్ను బ్రౌజర్ ఎడిటర్లో పేస్ట్ చేసి రన్ చేయండి. వేర్వేరు సమయాలు మరియు యూజర్లను ఇచ్చి డూప్లికేట్ అల్గారిథమ్ ఎలా రియాక్ట్ అవుతుందో స్వయంగా చూడండి!
12 🛑 బిగినర్స్ చేసే 7 ఘోరమైన లూప్ తప్పులు
లూప్ కంట్రోల్ రాసేటప్పుడు అత్యధికంగా జరిగే 7 తప్పులు:
break; కేవలం అది ఉన్న తక్షణ లోపలి లూప్ను మాత్రమే రద్దు చేస్తుంది. బయటి లూప్ నడుస్తూనే ఉంటుంది.
while (i < 10) { if (x) continue; i++; } రాస్తే i++ దాటిపోవడం వల్ల i పెరగక శాశ్వత ఇన్ఫినిట్ లూప్ అవుతుంది!
పెద్ద కలెక్షన్లలో రెండు లూప్స్ రాస్తే సర్వర్ రెస్పాన్స్ సమయం సెకన్ల నుండి నిమిషాలకు పడిపోతుంది. హాష్ సెట్స్ లేదా డిక్షనరీలు వాడాలి.
లూప్ లోపల ప్రతిసారీ డేటాబేస్ కనెక్షన్ లేదా ఫైల్ ఓపెన్ చేస్తే కనెక్షన్ పూల్ ఖాళీ అయిపోతుంది. కనెక్షన్ను లూప్ వెలుపల ఉంచండి.
మల్టీ-లెవల్ లూప్ బ్రేక్ మినహా సాధారణ సందర్భాలలో goto వాడితే కోడ్ ఫ్లో అగమ్యగోచరంగా మారుతుంది.
బయటి లూప్లో ఫ్లాగ్ రీసెట్ చేయకపోతే ఒకసారి ఫ్లాగ్ ట్రూ అయిన తర్వాత తర్వాతి రౌండ్లలో లూప్స్ తిరగవు.
సమాంతర లూప్లో counter++ చేస్తే రేస్ కండిషన్స్ (Race Conditions) వస్తాయి. Interlocked.Increment వాడాలి.
13 🧠 ఇంటరాక్టివ్ సెల్ఫ్-అసెస్మెంట్ క్విజ్ (5 లోతైన ప్రాక్టికల్ ప్రశ్నలు & వివరణలు)
లూప్ కంట్రోల్ మరియు పెర్ఫార్మెన్స్పై మీ పట్టును పరీక్షించుకోండి:
❓ ప్రశ్న 1: break మరియు continue మధ్య ప్రధాన క్రియాత్మక తేడా ఏమిటి?
break మొత్తం లూప్ను అక్కడితో పూర్తిగా రద్దు చేసి బయటకు వచ్చేస్తుంది. continue కేవలం ఆ ఒక్క ప్రస్తుత రౌండ్ను మాత్రమే స్కిప్ చేసి వెంటనే తదుపరి రౌండ్ను ప్రారంభిస్తుంది.
❓ ప్రశ్న 2: నెస్టెడ్ లూప్ లోపల break రాస్తే బయటి లూప్ కూడా ఆగిపోతుందా?
break కేవలం అది ఉన్న లోపలి లూప్ను మాత్రమే రద్దు చేస్తుంది. బయటి లూప్ నుండి కూడా ఒకేసారి బయటపడాలంటే బూలియన్ ఫ్లాగ్, return, లేదా goto లేబుల్ వాడాలి.
❓ ప్రశ్న 3: 10,000 ఐటెమ్స్ ఉన్న అర్రేపై రెండు నెస్టెడ్ లూప్స్ రాస్తే మొత్తం ఎన్ని ఆపరేషన్స్ జరుగుతాయి?
❓ ప్రశ్న 4: Loop Invariant Code Motion అంటే ఏమిటి?
Math.Sqrt() లేదా స్ట్రింగ్ లెంగ్త్) లూప్ లోపల పదే పదే లెక్కించకుండా, లూప్ ప్రారంభానికి ముందే లెక్కించి వేరియబుల్లో నిల్వ ఉంచే ఆప్టిమైజేషన్ టెక్నిక్.
❓ ప్రశ్న 5: సాధారణ for లూప్ తో పోల్చితే Parallel.For ఎప్పుడు వాడాలి?
Parallel.For వాడాలి. ఒకదానిపై ఒకటి ఆధారపడని (Independent) భారీ గణితం లేదా ఇమేజ్ ప్రాసెసింగ్ ఉన్నప్పుడు ఇది అత్యుత్తమ ఫలితాలను ఇస్తుంది.