Lesson 1
Understanding Data Streams in C#
Understanding Data Streams

Warm greetings! This lesson introduces data streams, which are essentially continuous datasets. Imagine a weather station or a gaming application gathering data every second — both generate data streams! We will learn how to handle these data streams using C# by accessing individual elements, slicing segments, and converting these streams into strings for easier handling.

Representing Data Streams in C#

In C#, data streams can be represented using collections such as arrays or lists. We will use a class to encapsulate operations related to these data streams in our C# application. Let's consider a simple C# class named DataStream:

C#
1using System; 2using System.Collections.Generic; 3 4class DataStream 5{ 6 private List<Dictionary<string, int>> data; 7 8 public DataStream(List<Dictionary<string, int>> data) 9 { 10 this.data = data; 11 } 12}

To use this, we create a sample data stream as an instance of our DataStream class, where each element is a dictionary with key-value pairs:

C#
1class Program 2{ 3 static void Main() 4 { 5 var stream = new DataStream(new List<Dictionary<string, int>> 6 { 7 new Dictionary<string, int> { {"id", 1}, {"value", 100} }, 8 new Dictionary<string, int> { {"id", 2}, {"value", 200} }, 9 new Dictionary<string, int> { {"id", 3}, {"value", 300} }, 10 new Dictionary<string, int> { {"id", 4}, {"value", 400} } 11 }); 12 } 13}
Accessing Elements — Key Operation

To look into individual elements of a data stream, we use zero-based indexing. The Get method we introduce below fetches the i-th element from the data stream:

C#
1using System; 2using System.Collections.Generic; 3 4class DataStream 5{ 6 private List<Dictionary<string, int>> data; 7 8 public DataStream(List<Dictionary<string, int>> data) 9 { 10 this.data = data; 11 } 12 13 public Dictionary<string, int> Get(int i) 14 { 15 if (i >= 0 && i < data.Count) 16 return data[i]; 17 18 return null; // Returning null if index is out of bounds 19 } 20}

Here's how we can use the Get method:

C#
1class Program 2{ 3 static void Main() 4 { 5 var stream = new DataStream(new List<Dictionary<string, int>> 6 { 7 new Dictionary<string, int> { {"id", 1}, {"value", 100} }, 8 new Dictionary<string, int> { {"id", 2}, {"value", 200} }, 9 new Dictionary<string, int> { {"id", 3}, {"value", 300} }, 10 new Dictionary<string, int> { {"id", 4}, {"value", 400} } 11 }); 12 13 var element = stream.Get(2); 14 if (element != null) 15 Console.WriteLine(element["id"]); // Output: 3 16 17 element = stream.Get(-1); 18 Console.WriteLine(element == null); // Output: True 19 } 20}

In essence, stream.Get(2) fetches us the dictionary with { "id": 3, "value": 300 }.

Slicing — A Useful Technique

To fetch a range of elements, we can use slicing. C# offers several ways to achieve this, such as using LINQ to select a range from our data stream. Here's how you might implement a Slice method:

C#
1using System; 2using System.Collections.Generic; 3using System.Linq; 4 5class DataStream 6{ 7 private List<Dictionary<string, int>> data; 8 9 public DataStream(List<Dictionary<string, int>> data) 10 { 11 this.data = data; 12 } 13 14 public List<Dictionary<string, int>> Get(int i) 15 { 16 if (i >= 0 && i < data.Count) 17 return data[i]; 18 19 return null; // Returning null if index is out of bounds 20 } 21 22 public List<Dictionary<string, int>> Slice(int i, int j) 23 { 24 return data.Skip(i).Take(j - i).ToList(); 25 } 26}

Here's a quick usage example:

C#
1class Program 2{ 3 static void Main() 4 { 5 var stream = new DataStream(new List<Dictionary<string, int>> 6 { 7 new Dictionary<string, int> { {"id", 1}, {"value", 100} }, 8 new Dictionary<string, int> { {"id", 2}, {"value", 200} }, 9 new Dictionary<string, int> { {"id", 3}, {"value", 300} }, 10 new Dictionary<string, int> { {"id", 4}, {"value", 400} } 11 }); 12 13 var slicedStream = stream.Slice(1, 3); 14 foreach (var item in slicedStream) 15 { 16 Console.WriteLine(item["id"]); // Output: 2, 3 17 } 18 } 19}
Transforming Data Streams to String — Another Key Operation

For better readability, we may want to convert our data streams into strings. In C#, we can use String.Join along with JSON serialization for this. Below is the example of implementing the ToString method:

C#
1using System; 2using System.Collections.Generic; 3using System.Text.Json; 4 5class DataStream 6{ 7 private List<Dictionary<string, int>> data; 8 9 public DataStream(List<Dictionary<string, int>> data) 10 { 11 this.data = data; 12 } 13 14 public Dictionary<string, int> Get(int i) 15 { 16 if (i >= 0 && i < data.Count) 17 return data[i]; 18 19 return null; 20 } 21 22 public List<Dictionary<string, int>> Slice(int i, int j) 23 { 24 return data.Skip(i).Take(j - i).ToList(); 25 } 26 27 public override string ToString() 28 { 29 var serializedItems = data.Select(item => JsonSerializer.Serialize(item)); 30 return "[" + string.Join(", ", serializedItems) + "]"; 31 } 32}

To demonstrate:

C#
1class Program 2{ 3 static void Main() 4 { 5 var stream = new DataStream(new List<Dictionary<string, int>> 6 { 7 new Dictionary<string, int> { {"id", 1}, {"value", 100} }, 8 new Dictionary<string, int> { {"id", 2}, {"value", 200} }, 9 new Dictionary<string, int> { {"id", 3}, {"value", 300} }, 10 new Dictionary<string, int> { {"id", 4}, {"value", 400} } 11 }); 12 13 Console.WriteLine(stream.ToString()); 14 // Output: [{"id":1,"value":100},{"id":2,"value":200},{"id":3,"value":300},{"id":4,"value":400}] 15 } 16}
Summary

In this lesson, we explored data streams and how to represent and manipulate them using C# collections like lists. We crafted a class that encapsulates operations on data streams in C#, including accessing elements, slicing ranges, and converting streams to string representations.

Now it's time to apply your newfound knowledge in the practice exercises that follow!

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.