Przejdź do treści stopki
POMOC .NET

C# foreach z indeksem (Jak to dziala dla programistow)

W języku C# instrukcja foreach jest zazwyczaj używana do iteracji nad kolekcjami, takimi jak tablice, listy lub inne typy wyliczalne. Jednak jednym z ograniczeń jest to, że pętla foreach nie zapewnia wbudowanej zmiennej indeksowej do śledzenia bieżącej iteracji. Programiści często potrzebują dostępu do indeksu bieżącego elementu. Poniżej omówimy różne sposoby wdrożenia tej funkcjonalności oraz biblioteki IronPDF.

Podstawy pętli foreach

Pętla foreach została zaprojektowana w celu uproszczenia iteracji przez tablice, listy, słowniki i inne typy, które implementują interfejs IEnumerable. Oto podstawowy przykład wykorzystania instrukcji foreach do iteracji po tablicy danych typu integer:

int[] numbers = { 10, 20, 30, 40 };
foreach (int number in numbers)
{
    Console.WriteLine(number);
}
int[] numbers = { 10, 20, 30, 40 };
foreach (int number in numbers)
{
    Console.WriteLine(number);
}
Dim numbers() As Integer = { 10, 20, 30, 40 }
For Each number As Integer In numbers
	Console.WriteLine(number)
Next number
$vbLabelText   $csharpLabel

W tym przykładzie number reprezentuje element kolekcji podczas każdej iteracji. Pętla automatycznie przechodzi przez wszystkie elementy tablicy. Nie ma jednak wbudowanego sposobu na uzyskanie dostępu do indeksu bieżącego elementu.

Obsługa indeksu w pętli foreach

Chociaż język C# nie udostępnia bezpośrednio indeksu w pętli foreach, istnieje kilka technik, które pozwalają rozwiązać ten problem. Omówmy te metody szczegółowo.

Metoda 1: Użycie oddzielnej zmiennej

Jednym z najprostszych sposobów uzyskania indeksu bieżącego elementu jest użycie zewnętrznej zmiennej indeksowej. Będziesz musiał zwiększać tę wartość ręcznie w pętli:

int[] numbers = { 10, 20, 30, 40 };
int numberIndex = 0;
foreach (int number in numbers)
{
    Console.WriteLine($"Index: {numberIndex}, Value: {number}");
    numberIndex++;
}
int[] numbers = { 10, 20, 30, 40 };
int numberIndex = 0;
foreach (int number in numbers)
{
    Console.WriteLine($"Index: {numberIndex}, Value: {number}");
    numberIndex++;
}
Dim numbers() As Integer = { 10, 20, 30, 40 }
Dim numberIndex As Integer = 0
For Each number As Integer In numbers
	Console.WriteLine($"Index: {numberIndex}, Value: {number}")
	numberIndex += 1
Next number
$vbLabelText   $csharpLabel

W tym kodzie zmienna index jest inicjowana przed rozpoczęciem pętli, a następnie zwiększana wewnątrz pętli podczas każdej iteracji. Chociaż takie podejście się sprawdza, wymaga ręcznego utrzymywania indeksu, co nie zawsze jest idealnym rozwiązaniem.

Metoda 2: Korzystanie z metody Select w LINQ

Metoda Select języka LINQ może służyć do rzutowania każdego elementu kolekcji na nową formę, w tym jego indeks. Oto przykład:

int[] numbers = { 10, 20, 30, 40 };
foreach (var item in numbers.Select((value, index) => new { value, index }))
{
    Console.WriteLine($"Index: {item.index}, Value: {item.value}");
}
int[] numbers = { 10, 20, 30, 40 };
foreach (var item in numbers.Select((value, index) => new { value, index }))
{
    Console.WriteLine($"Index: {item.index}, Value: {item.value}");
}
Dim numbers() As Integer = { 10, 20, 30, 40 }
For Each item In numbers.Select(Function(value, index) New With {
	Key value,
	Key index
})
	Console.WriteLine($"Index: {item.index}, Value: {item.value}")
Next item
$vbLabelText   $csharpLabel

W tym przykładzie Select tworzy obiekt anonimowy, który zawiera zarówno wartość bieżącego elementu, jak i jego indeks. Pętla foreach może następnie iterować po tych obiektach i uzyskać bezpośredni dostęp zarówno do indeksu, jak i wartości.

Metoda 3: Korzystanie z niestandardowego iteratora

Można zaimplementować niestandardową metodę rozszerzenia iteratora przy użyciu słowa kluczowego yield return, aby wygenerować metodę, która zwraca zarówno bieżący element, jak i jego indeks. Jest to nieco bardziej zaawansowane rozwiązanie, ale oferuje większą elastyczność.

public static IEnumerable<(int index, T value)> WithIndex<t>(this IEnumerable<t> source)
{
    int index = 0;
    foreach (T value in source)
    {
        yield return (index, value);
        index++;
    }
}
public static IEnumerable<(int index, T value)> WithIndex<t>(this IEnumerable<t> source)
{
    int index = 0;
    foreach (T value in source)
    {
        yield return (index, value);
        index++;
    }
}
Imports System.Collections.Generic

Public Module Extensions
    <System.Runtime.CompilerServices.Extension> 
    Public Iterator Function WithIndex(Of T)(source As IEnumerable(Of T)) As IEnumerable(Of (index As Integer, value As T))
        Dim index As Integer = 0
        For Each value As T In source
            Yield (index, value)
            index += 1
        Next
    End Function
End Module
$vbLabelText   $csharpLabel

Teraz możesz używać tej metody rozszerzenia w swoich kolekcjach:

int[] numbers = { 10, 20, 30, 40 };
foreach (var (index, value) in numbers.WithIndex())
{
    Console.WriteLine($"Index: {index}, Value: {value}");
}
int[] numbers = { 10, 20, 30, 40 };
foreach (var (index, value) in numbers.WithIndex())
{
    Console.WriteLine($"Index: {index}, Value: {value}");
}
Dim numbers() As Integer = { 10, 20, 30, 40 }
foreach var(index, value) In numbers.WithIndex()
	Console.WriteLine($"Index: {index}, Value: {value}")
Next
$vbLabelText   $csharpLabel

Takie podejście stanowi bardziej eleganckie rozwiązanie problemu foreach z indeksem poprzez wyodrębnienie ręcznego zarządzania indeksem do metody wielokrotnego użytku.

Użycie pętli while do uzyskania dostępu do indeksów

Jeśli pracujesz z kolekcjami, takimi jak tablice lub listy, możesz użyć pętli while w połączeniu ze zmienną indeksową, aby uzyskać dostęp zarówno do indeksu, jak i bieżącego elementu:

int[] numbers = { 10, 20, 30, 40 };
int index = 0;
while (index < numbers.Length)
{
    Console.WriteLine($"Index: {index}, Value: {numbers[index]}");
    index++;
}
int[] numbers = { 10, 20, 30, 40 };
int index = 0;
while (index < numbers.Length)
{
    Console.WriteLine($"Index: {index}, Value: {numbers[index]}");
    index++;
}
Dim numbers() As Integer = { 10, 20, 30, 40 }
Dim index As Integer = 0
Do While index < numbers.Length
	Console.WriteLine($"Index: {index}, Value: {numbers(index)}")
	index += 1
Loop
$vbLabelText   $csharpLabel

C# foreach z indeksem (jak to działa dla programistów): Rysunek 1 – Wyniki indeksów

Ta metoda pozwala na bezpośredni dostęp zarówno do indeksu, jak i do bieżącego elementu poprzez użycie zmiennej indeksu jako indeksu dolnego dla tablicy lub listy.

Niestandardowe kolekcje i iteratory w .NET

Jeśli pracujesz z niestandardowymi kolekcjami, możesz zaimplementować własne iteratory, aby obsługiwały dostęp indeksowany. Wdrażając interfejs IEnumerable i używając instrukcji yield return, można tworzyć iteratory, które zwracają zarówno element, jak i jego indeks.

Oto przykład tworzenia niestandardowej kolekcji, która implementuje interfejs IEnumerable:

public class CustomCollection<t> : IEnumerable<t>
{
    private T[] _items;
    public CustomCollection(T[] items)
    {
        _items = items;
    }
    public IEnumerator<t> GetEnumerator()
    {
        for (int i = 0; i < _items.Length; i++)
        {
            yield return _items[i];
        }
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}
public class CustomCollection<t> : IEnumerable<t>
{
    private T[] _items;
    public CustomCollection(T[] items)
    {
        _items = items;
    }
    public IEnumerator<t> GetEnumerator()
    {
        for (int i = 0; i < _items.Length; i++)
        {
            yield return _items[i];
        }
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}
Imports System.Collections
Imports System.Collections.Generic

Public Class CustomCollection(Of T)
    Implements IEnumerable(Of T)

    Private _items As T()

    Public Sub New(items As T())
        _items = items
    End Sub

    Public Function GetEnumerator() As IEnumerator(Of T) Implements IEnumerable(Of T).GetEnumerator
        For i As Integer = 0 To _items.Length - 1
            Yield _items(i)
        Next
    End Function

    Private Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
        Return GetEnumerator()
    End Function
End Class
$vbLabelText   $csharpLabel

Następnie można użyć tej niestandardowej kolekcji w pętli foreach:

var customCollection = new CustomCollection<int>(new int[] { 10, 20, 30, 40 });
foreach (int number in customCollection)
{
    Console.WriteLine(number);
}
var customCollection = new CustomCollection<int>(new int[] { 10, 20, 30, 40 });
foreach (int number in customCollection)
{
    Console.WriteLine(number);
}
Dim customCollection As New CustomCollection(Of Integer)(New Integer() { 10, 20, 30, 40 })
For Each number As Integer In customCollection
	Console.WriteLine(number)
Next number
$vbLabelText   $csharpLabel

Wdrażając metodę GetEnumerator i używając yield return, tworzysz iterator, który pozwala pętli foreach pracować z twoją niestandardową kolekcją tak samo, jak z każdą inną kolekcją w .NET.

Korzystanie ze słowników i iteracja z parami klucz-wartość

Podczas pracy ze słownikami pętla foreach pozwala na bezpośrednie iterowanie po parach klucz-wartość. Jest to typowy przypadek użycia umożliwiający dostęp zarówno do klucza, jak i wartości podczas każdej iteracji:

Dictionary<int, string> dict = new Dictionary<int, string>
{
    { 1, "Apple" },
    { 2, "Banana" },
    { 3, "Cherry" }
};
foreach (var kvp in dict)
{
    Console.WriteLine($"Key: {kvp.Key}, Value: {kvp.Value}");
}
Dictionary<int, string> dict = new Dictionary<int, string>
{
    { 1, "Apple" },
    { 2, "Banana" },
    { 3, "Cherry" }
};
foreach (var kvp in dict)
{
    Console.WriteLine($"Key: {kvp.Key}, Value: {kvp.Value}");
}
Dim dict As New Dictionary(Of Integer, String) From {
	{1, "Apple"},
	{2, "Banana"},
	{3, "Cherry"}
}
For Each kvp In dict
	Console.WriteLine($"Key: {kvp.Key}, Value: {kvp.Value}")
Next kvp
$vbLabelText   $csharpLabel

W tym przykładzie kvp.Key podaje aktualny klucz, a kvp.Value podaje aktualną wartość.

Korzystanie z IronPDF z pętlą foreach i indeksem w języku C

C# foreach z indeksem (jak to działa dla programistów): Rysunek 2 – IronPDF

IronPDF to biblioteka PDF służąca do generowania plików PDF z HTML oraz wykonywania innych zadań związanych z PDF w języku C#. Jest również kompatybilny z najnowszym .NET Framework. Podczas generowania plików PDF za pomocą IronPDF może zaistnieć potrzeba iteracji nad zbiorem danych i dynamicznego wstawiania treści do pliku PDF. Połączenie pętli foreach z obsługą indeksów pozwala zarządzać pozycjonowaniem, numeracją lub niestandardową logiką w oparciu o indeks bieżącego elementu w zbiorze. Oto praktyczny przykład wykorzystania IronPDF do utworzenia pliku PDF, w którym każdy element kolekcji jest wstawiany do dokumentu wraz z indeksem.

using IronPdf;
class Program
{
    static void Main(string[] args)
    {
        // Create a new PDF document renderer
        var pdf = new ChromePdfRenderer();

        // Sample data array
        string[] items = { "First Item", "Second Item", "Third Item" };

        // Initialize the HTML content with foreach loop and index
        string htmlContent = "<html><body>";
        int index = 0;
        foreach (var item in items)
        {
            htmlContent += $"<h2>Item {index + 1}: {item}</h2>";
            index++;
        }
        htmlContent += "</body></html>";

        // Render the HTML to PDF
        var pdfDocument = pdf.RenderHtmlAsPdf(htmlContent);

        // Save the PDF document
        pdfDocument.SaveAs("output.pdf");

        // Notify completion
        Console.WriteLine("PDF created successfully with indexed items.");
    }
}
using IronPdf;
class Program
{
    static void Main(string[] args)
    {
        // Create a new PDF document renderer
        var pdf = new ChromePdfRenderer();

        // Sample data array
        string[] items = { "First Item", "Second Item", "Third Item" };

        // Initialize the HTML content with foreach loop and index
        string htmlContent = "<html><body>";
        int index = 0;
        foreach (var item in items)
        {
            htmlContent += $"<h2>Item {index + 1}: {item}</h2>";
            index++;
        }
        htmlContent += "</body></html>";

        // Render the HTML to PDF
        var pdfDocument = pdf.RenderHtmlAsPdf(htmlContent);

        // Save the PDF document
        pdfDocument.SaveAs("output.pdf");

        // Notify completion
        Console.WriteLine("PDF created successfully with indexed items.");
    }
}
Imports IronPdf
Friend Class Program
	Shared Sub Main(ByVal args() As String)
		' Create a new PDF document renderer
		Dim pdf = New ChromePdfRenderer()

		' Sample data array
		Dim items() As String = { "First Item", "Second Item", "Third Item" }

		' Initialize the HTML content with foreach loop and index
		Dim htmlContent As String = "<html><body>"
		Dim index As Integer = 0
		For Each item In items
			htmlContent &= $"<h2>Item {index + 1}: {item}</h2>"
			index += 1
		Next item
		htmlContent &= "</body></html>"

		' Render the HTML to PDF
		Dim pdfDocument = pdf.RenderHtmlAsPdf(htmlContent)

		' Save the PDF document
		pdfDocument.SaveAs("output.pdf")

		' Notify completion
		Console.WriteLine("PDF created successfully with indexed items.")
	End Sub
End Class
$vbLabelText   $csharpLabel

Oto plik PDF z tłumaczeniem:

C# foreach z indeksem (jak to działa dla programistów): Rysunek 3 – Wynik w formacie PDF

Wnioski

C# foreach z indeksem (jak to działa dla programistów): Rysunek 4 – Licencjonowanie

W języku C# pętla foreach jest wygodnym sposobem iteracji nad kolekcjami, ale nie ma natywnej obsługi indeksowania. Istnieje jednak kilka sposobów na obejście tego ograniczenia. Niezależnie od tego, czy używasz prostej zmiennej indeksowej, metody Select z LINQ, czy niestandardowych iteratorów, możesz uzyskać dostęp do indeksu bieżącego lub następnego elementu podczas iteracji. Zrozumienie tych technik może pomóc w bardziej efektywnym wykorzystaniu pętli foreach, zwłaszcza gdy trzeba znać indeks każdego elementu.

Dzięki IronPDF nie musisz od razu podejmować decyzji. Oferujemy bezpłatną wersję próbną, która pozwala dogłębnie poznać możliwości oprogramowania. Jeśli podoba Ci się to, co widzisz, ceny licencji zaczynają się od $799.

Często Zadawane Pytania

Jak mogę śledzić indeks elementów w pętli foreach w języku C#?

Aby śledzić indeks w pętli foreach w języku C#, można ręcznie zwiększać wartość oddzielnej zmiennej indeksowej, użyć metody Select języka LINQ do wyświetlania elementów wraz z ich indeksem lub utworzyć niestandardowy iterator, który zwraca zarówno element, jak i jego indeks.

Czym jest metoda LINQ Select i w jaki sposób pomaga w indeksowaniu?

Metoda LINQ Select może przekształcić każdy element w kolekcji w nową formę, która zawiera indeks elementu. Ta projekcja pozwala na dostęp zarówno do elementu, jak i jego indeksu podczas iteracji w pętli foreach.

Jak mogę utworzyć niestandardowy iterator do indeksowania w języku C#?

Niestandardowy iterator w języku C# można utworzyć za pomocą słowa kluczowego yield return. Pozwala to na zbudowanie metody, która iteruje nad kolekcją i zwraca zarówno bieżący element, jak i jego indeks, upraszczając indeksowanie pętli.

Czy biblioteka PDF może pomóc w tworzeniu indeksowanych treści w języku C#?

Tak, biblioteka PDF, taka jak IronPDF, może być używana wraz z pętlą foreach w języku C# do iteracji nad zbiorami danych i wstawiania indeksowanej treści do pliku PDF. Takie podejście pozwala na dynamiczne pozycjonowanie treści i precyzyjne indeksowanie.

Jak iterować po słowniku za pomocą pętli foreach w języku C#?

W języku C# pętla foreach może iterować po słowniku, uzyskując dostęp do każdej pary klucz-wartość. Pozwala to programistom na bezpośrednią pracę zarówno z kluczami, jak i wartościami podczas procesu iteracji.

Jakie są zalety korzystania z bibliotek PDF w programowaniu w języku C#?

Biblioteki PDF umożliwiają programistom generowanie plików PDF z HTML oraz wykonywanie różnych operacji na plikach PDF w języku C#. Zazwyczaj oferują one bezpłatne wersje próbne, które pozwalają zapoznać się z funkcjami, a licencje są dostępne do zakupu.

W jaki sposób pętla while może być wykorzystana do iteracji indeksowanej w języku C#?

Pętla while może być używana z zmienną indeksową do iteracji nad kolekcjami w języku C#, zapewniając dostęp zarówno do indeksu, jak i bieżącego elementu poprzez wykorzystanie indeksu jako indeksu dolnego.

Jacob Mellor, Dyrektor Technologiczny @ Team Iron
Dyrektor ds. technologii

Jacob Mellor jest Chief Technology Officer w Iron Software i wizjonerskim inżynierem, pionierem technologii C# PDF. Jako pierwotny deweloper głównej bazy kodowej Iron Software, kształtuje architekturę produktów firmy od jej początku, przekształcając ją wspólnie z CEO Cameron Rimington w firmę liczą...

Czytaj więcej

Zespol wsparcia Iron

Jestesmy online 24 godziny, 5 dni w tygodniu.
Czat
Email
Zadzwon do mnie