Skip to content
Dunking Dog Games Dunking Dog Games

Exploring Ruby's times() Function in C#/Unity

· C# , Blog , Unity

Ruby times function in C# guide

Introduction

In the world of programming, different languages often have their own unique features and functions that make them stand out. Ruby, a dynamically-typed scripting language known for its simplicity and elegance, has a handy function called times() that allows you to execute a block of code a specified number of times.

But what if you’re working in C#, particularly in the context of Unity game development? Is there a way to achieve the same functionality? In this blog post, we’ll explore how you can replicate Ruby’s times() function in C#/Unity.

Ruby’s times() Function – A Quick Refresher

Ruby’s times() method is elegant and concise:

5.times { |i| puts "Iteration #{i}" }
# Output:
# Iteration 0
# Iteration 1
# Iteration 2
# Iteration 3
# Iteration 4

This single line replaces what would otherwise require a traditional loop. The beauty of times() lies in its readability and the fact that it automatically handles the iteration counter.

Replicating times() in C#

C# doesn’t have a built-in times() method, but we can create one using extension methods and delegates. Here are several approaches:

Approach 1: Simple Extension Method

using System;

public static class IntegerExtensions
{
    public static void Times(this int count, Action<int> action)
    {
        for (int i = 0; i < count; i++)
        {
            action(i);
        }
    }
}

// Usage in Unity:
void Start()
{
    5.Times(i => Debug.Log($"Iteration {i}"));
}

This is the closest equivalent to Ruby’s times() and provides clean, readable code.

Approach 2: With Return Value (Select Equivalent)

If you need to collect results from each iteration:

using System;
using System.Collections.Generic;

public static class IntegerExtensions
{
    public static IEnumerable<TResult> Times<TResult>(this int count, Func<int, TResult> selector)
    {
        var results = new List<TResult>();
        for (int i = 0; i < count; i++)
        {
            results.Add(selector(i));
        }
        return results;
    }
}

// Usage:
void Start()
{
    var numbers = 5.Times(i => i * i); // [0, 1, 4, 9, 16]
    foreach (var num in numbers)
    {
        Debug.Log(num);
    }
}

Approach 3: Using LINQ (Unity 2021+)

For projects using modern .NET or Unity’s IL2CPP with LINQ support:

using System.Linq;

void Start()
{
    Enumerable.Range(0, 5).Each(i => Debug.Log($"Iteration {i}"));
    
    // Or with LINQ's built-in methods:
    var results = Enumerable.Range(0, 5)
        .Select(i => i * 2)
        .ToList(); // [0, 2, 4, 6, 8]
}

⚠️ Note: LINQ may not be available in all Unity configurations. Check your project’s .NET version compatibility.

Practical Unity Examples

Example 1: Spawning Multiple Objects

using UnityEngine;

public class ObjectSpawner : MonoBehaviour
{
    public GameObject prefab;
    public int count = 10;
    public float spacing = 2f;

    void Start()
    {
        count.Times(i =>
        {
            Vector3 position = new Vector3(i * spacing, 0, 0);
            Instantiate(prefab, position, Quaternion.identity);
        });
    }
}

Example 2: Creating UI Elements

using UnityEngine;
using UnityEngine.UI;

public class UISpawner : MonoBehaviour
{
    public GameObject buttonPrefab;
    public Transform parentPanel;
    public int itemCount = 5;

    void Start()
    {
        itemCount.Times(i =>
        {
            var button = Instantiate(buttonPrefab, parentPanel);
            button.GetComponent<Text>().text = $"Item {i + 1}";
        });
    }
}

Example 3: Initializing Arrays or Lists

using System.Collections.Generic;
using UnityEngine;

public class ListInitializer : MonoBehaviour
{
    void Start()
    {
        var scores = new List<int>();
        
        // Initialize with default values
        10.Times(i => scores.Add(0));
        
        Debug.Log($"List has {scores.Count} elements"); // Output: 10
    }
}

Example 4: Coroutine-Based Timing

Combine times() with Unity coroutines for timed sequences:

using System.Collections;
using UnityEngine;

public class TimedSequence : MonoBehaviour
{
    void Start()
    {
        StartCoroutine(PlaySequence());
    }

    IEnumerator PlaySequence()
    {
        5.Times(i =>
        {
            Debug.Log($"Step {i + 1}");
            // Note: This runs synchronously; for async timing, see below
        });
        
        yield return null;
    }
}

// For timed steps between iterations:
IEnumerator PlayTimedSequence()
{
    for (int i = 0; i < 5; i++)
    {
        Debug.Log($"Step {i + 1}");
        yield return new WaitForSeconds(1f);
    }
}

Comparison: Ruby vs C# Iteration Styles

FeatureRuby times()C# Extension MethodTraditional Loop
Syntax5.times { |i| ... }5.Times(i => ...)for (int i=0; i<5; i++)
ReadabilityExcellentVery GoodGood
FlexibilityHighHighHighest
PerformanceGoodGoodBest
Learning CurveEasyModerateEasy

When to Use Each Approach

Use Extension Method times() When:

  • You want clean, Ruby-like syntax in C#
  • The iteration logic is simple and self-contained
  • Code readability is a priority

Use Traditional Loop When:

  • Performance is critical (micro-optimizations)
  • You need early exit (break) or skip (continue)
  • Complex nested iterations

Use LINQ When:

  • You’re transforming data collections
  • Your project supports modern .NET
  • You prefer functional programming style

Best Practices

  1. Keep extension methods simple: Avoid complex logic inside times() callbacks
  2. Use meaningful variable names: count.Times(i => ...) is clearer than n.Times(x => ...)
  3. Be aware of performance: Extension methods add a tiny overhead; negligible for most games
  4. Document your extensions: Add XML comments so other developers understand the API

Which iteration style do you prefer in your Unity projects? Share your thoughts in the comments! 💻✨

Tags: c#unity