C3 AI Documentation Home

C3 AI Type System Collections

A C3 AI Collection is a data structure that holds elements of a specific ValueType, much like collections in other programming languages. C3 AI collections are similar to language-native collections, such as lists and dictionaries in Python or Arrays and Maps in JavaScript. However, C3 AI collections offer the added benefits of being interoperable across languages and providing additional helper methods.

C3 AI collections are immutable, meaning they cannot be modified once created. This immutability ensures that data remains consistent and thread-safe. Builders are introduced as a solution for creating or modifying collections, allowing you to build a new collection starting from an existing one or from a lambda.

In contrast, the CollectionType, including the ValueType, describes C3 AI values. Instances of ValueTypes act as the metadata for your data model.

At the core of the collections are three distinct but interrelated constructs:

Note: There is no StreamBuilder Type. Streams do not require a builder because their processing model is fundamentally different. Data elements are processed as they are received, and there is no need to gather all elements beforehand. This makes streams more suitable for handling large-scale or real-time data processing.

Advantages C3 AI collections

Using collections offers several advantages:

  • Type Safety: Collections are explicitly typed, reducing the risk of runtime errors.

  • Immutability: Collections are immutable, preventing accidental modifications.

  • Consistency: A unified API for different types of collections, making your codebase more consistent and easier to maintain.

Immutability

JavaScript
var jsArray = [1, 2, 3];
JavaScript
var c3Array = ArrayType.ofInt().makeArray(jsArray);

You can modify the native JavaScript array:

JavaScript
jsArray[0] = 10; // Modify an element
jsArray.push(4); // Add an element
jsArray.pop();   // Remove the last element
jsArray // [10, 2, 3]

However, you cannot modify c3Array since it's immutable.

C3 AI collections relative to other language native collections

C3 AI collections are designed to be interoperable with native collections from different programming languages. This means you can convert C3 AI collections to and from their native counterparts (for example, converting a C3 AI Array to a JavaScript Array or a C3 AI Map to a Python dictionary). This flexibility makes C3 AI collections highly versatile for multi-language projects.

How to access one element in a C3 AI collection

You can access elements in a C3 AI Collection similarly to how you would with native collections. For example, in a C3 AI Array, you can access an element by its index.

JavaScript
// Access an element in a C3 array
var element = c3Array.get(0);
Python
# Access an element in a C3 array
element = arr.get(0)

How to iterate through elements in a C3 AI collection

C3 AI Collections provide methods for iterating through their elements, similar to native collection types. For example, you can use the forEach method in JavaScript or Python to process each element in a collection.

JavaScript
// Iterate through elements in a C3 AI Array
c3Array.forEach(function (element) {
    console.log(element);
});
Python
# Iterate through elements in a C3 array
c3Array.forEach(lambda element: print(element))

Convert native collections to C3 AI collections and vice versa

C3 AI collections can be easily converted to and from their language-native counterparts. This is particularly useful when working across different languages or integrating C3 AI collections with existing codebases.

For example, converting a JavaScript array to a C3 AI Array:

JavaScript
// Convert a native JavaScript array to a C3 array
var jsArray = [1, 2, 3];
var c3Array = ArrayType.ofInt().makeArray(jsArray);

Converting a C3 AI Array to a JavaScript Array:

JavaScript
// Convert a C3 array to a native JavaScript array
var nativeArray = c3Array.toNative();

In Python:

Python
# Convert a native Python list to a C3 array
py_list = [1, 2, 3]
c3_array = c3.ArrayType.ofInt().makeArray(py_list)

# Convert a C3 array to a native Python list
native_list = c3_array.toNative()

Finding available methods on collections

To discover other methods available on C3 Collections, you can refer to the meta-Types associated with each collection type, such as ArrayType, SetType, or MapType. These meta-Types define the blueprint for their corresponding collection types and list all available methods and properties.

For example, you can retrieve the metadata for the Automobile Type to explore its fields and methods:

JavaScript
// Retrieve metadata of the 'Garage' type
Automobile.meta();
Python
# Retrieve metadata of the 'Garage' type
c3.Automobile.meta()

Add reference to topic on TypeMeta

Collection Types

The Collection Types Array, Set, Map, Stream represent the actual data structures you interact with in your applications. These Types provide a range of methods for adding, removing, and accessing elements within a collection of elements.

For instance:

  • Array: A one-dimensional, ordered collection that allows duplicates.
  • Set: An unordered collection that does not allow duplicates.
  • Map: A collection of key-value pairs where each key is unique.
  • Stream: A sequence of elements that can be processed in a functional style.

These Collection Types encapsulate the core functionalities and behaviors of the respective data structures, making them easy to work with for everyday operations.

Meta-Types

The meta-Types ArrayType, SetType, MapType, StreamType define the blueprint for their corresponding collection Types. They specify the rules, constraints, and characteristics that the Collection Types must adhere to. The meta-Types also provide factory methods for creating instances of the collections and builders. For example:

  • ArrayType: Defines the structure and behavior for all Array instances.
  • SetType: Specifies the rules for creating and manipulating Sets.
  • MapType: Outlines the structure for Maps, including the key and value types.
  • StreamType: Establishes the characteristics of Streams.

The meta-Types ensure consistency and standardization across all instances of a particular collection Type, enabling the C3 Type System to maintain a cohesive and predictable behavior for collections.

Difference between Type and CollectionType

A C3 Type functions like a class. You can instantiate Types, declare methods on Types, call methods on Types and Type instances, and set fields on instances of Types.

In contrast, the CollectionType, including the ValueType, describes C3 values. Instances of ValueTypes act as the metadata for your data model.

For example, if you declare a Type with the following field:

Type
type Garage {
    automobiles: [Automobile]
}

Expect metadata that says, the field on Garage named automobiles is an Array of Automobiles. This metadata is described using instances of ValueTypes. The TypeMeta for Garage has a FieldType for the automobiles field, whose valueType is an instance of ArrayType. The ArrayType instance has its elementType field set to the ReferenceType for Automobile.

The assertions below demonstrate these statements:

JavaScript
// Retrieve metadata of the 'Garage' type
garageTypeMeta = c3.Garage.meta();

// Retrieve the field type of 'automobiles' field from the 'Garage' metadata
ft = garageTypeMeta.fieldType('automobiles');

// Retrieve the value type of the 'automobiles' field type
at = ft.valueType();

This code snippet above retrieves the metadata for the Garage Type and verifies that the automobiles field is an array of Automobile references.

Builders

The builders ArrayBuilder, SetBuilder, MapBuilder are specialized constructs designed for constructing and manipulating instances of collections in a more controlled and flexible manner. They allow for batch operations and incremental modifications, which can be more efficient than manipulating the collection directly. Builders provide methods for adding, removing, and replacing elements, as well as more advanced operations like filtering and mapping.

For instance:

  • ArrayBuilder: Facilitates the creation and modification of Array instances.
  • SetBuilder: Enables batch operations and incremental modifications for Sets.
  • MapBuilder: Provides methods for constructing and manipulating Maps with key-value pairs.

Builders are especially useful when you need to construct a collection through a series of transformations or when dealing with large datasets that require multiple operations.

The absence of a StreamBuilder Type in the C3 Agentic AI Platform is linked to the inherent nature of streams. Streams are designed to handle data in a continuous flow, processing elements on-the-fly without needing to load the entire dataset into memory. This contrasts with collections like arrays, maps, and sets, which typically require a complete dataset to be assembled before they can be used.

Streaming content

Streams are intended for scenarios where data is either too large to fit into memory all at once or when the data is being produced and consumed in a dynamic manner. The key benefits of streams include:

  1. Memory Efficiency: Streams process data element-by-element, which significantly reduces memory overhead compared to loading entire collections.
  2. Lazy Evaluation: Data in streams is computed and provided only as needed. This can optimize performance by avoiding unnecessary computations.
  3. Continuous Data Processing: Streams are ideal for processing data that arrives in real-time or from a continuous source, such as log files, sensor data, or network sockets.

Stream vs. Collection Builders

  • ArrayBuilder, MapBuilder, SetBuilder: These builders are used to construct entire collections. They gather elements and provide methods to finalize and retrieve the complete collection. This approach is suitable for scenarios where the dataset size is manageable and can fit into memory.

    JavaScript
    // Example of using ArrayBuilder in JavaScript
    let arrayBuilder = new ArrayBuilder();
    arrayBuilder.append(1).append(2).append(3);
    let array = arrayBuilder.build();
    console.log(array);  // Output: [1, 2, 3]
  • Stream: Streams do not require a builder because their processing model is fundamentally different. Data elements are processed as they are received, and there is no need to gather all elements beforehand. This makes streams more suitable for handling large-scale or real-time data processing.

    JavaScript
    // Example of using a stream in JavaScript
    function processElement(element) {
        console.log(element);
    }
    
    ScadaEvent.fetchObjStream({
        filter: 'scadaNode == node1 && timestamp >= start && timestamp < end',
        include: '[this]',
    }).each(processElement);
    

Efficient stream handling: Avoiding memory issues

When you return a stream, for example, from Java to Python, there are two different ways to handle the stream: using py-client and py-server.

Here's what happens in each case:

  1. Returning a Stream to py-client from Java:

    • How It Works: The entire content of the stream is collected into Java's memory first.
    • Problem: For large files, this can cause Java to run out of memory because it tries to load everything at once.
    • What Happens Next: After collecting all the data, Python processes this data piece by piece.
  2. Returning a Stream to py-server from Java:

    • How It Works: The content of the stream is not fully loaded into Java's memory. Instead, it is handled directly on the server.
    • Advantage: This avoids memory issues with large files because the data is processed on the server without being fully loaded into memory.
    • Caution: If your server-side code then returns this stream back to py-client, you still face the memory issue. Therefore, you should process the stream on the server but not return it to the client.
Python
def foo(file):
    strm = file.readLines()
    nxt = strm.next()
    # Continue processing the stream
    ...

c3.Lambda.fromPyFunc(foo, 'py-server').call(myFile)

Key point to consider:

  • py-client: Risk of memory issues with large files because Java tries to load everything at once.
  • py-server: Avoids memory issues by processing the stream on the server without fully loading it into memory.
  • Use Case: Prefer processing streams on the server (py-server) and avoid returning large streams to the client to prevent memory issues.

Alternatives for py-client

Using the MapBuilder Type

The MapBuilder in the C3 Type System follows the builder pattern for creating collections. This approach allows you to work with a mutable builder instance for a particular map Type, and then convert it into a fully built immutable map using the build() method.

Here is how to use a MapBuilder to create a map of strings to doubles. This code snippet demonstrates creating a map builder for a map with string keys and double values, adding an entry, and retrieving values from the map.

JavaScript
// Create a MapBuilder for a map with string keys and double values
let b = MapType.ofStrTo(PrimitiveType.ofDbl()).makeBuilder();

// Add an entry to the map
b.put('pi', 3.14);

// Check the size of the map
console.log(b.size()); // Outputs the number of entries in the map

// Check if the map is empty
console.log(b.isEmpty()); // Outputs false since the map has entries

// Retrieve the value associated with the key 'pi'
console.log(b.current().get('pi')); // Outputs 3.14

This Python code snippet demonstrates creating a map builder for a map with string keys and double values, adding an entry, and retrieving values from the map.

Python
# Create a MapBuilder for a map with string keys and double values
b = c3.MapType.ofStrTo(c3.PrimitiveType.ofDbl()).makeBuilder()

# Add entries to the map
b.put('pi', 3.14)

# Check the size and content of the map
print(b.size())  # Outputs the number of entries in the map
print(b.isEmpty())  # Outputs False since the map has entries
print(b.current().get('pi'))  # Outputs 3.14

Setting fields using the builder pattern for an Obj Type

Builders in C3 are mutable objects that facilitate the construction of Obj Types or Collections. Each Obj subtype has a corresponding Builder subtype. For every field in an Obj Type, its Builder Type has a method with the same name, which allows setting the field's value. Builders can be created from a Type or an instance of a Type. Builders created from a Type instance inherit all the fields of the instance.

This snippet shows how to use the builder pattern to create and modify instances of Automobile in a mutable and flexible manner.

JavaScript
// Create a builder for the Automobile type
let myObjBuilder = Automobile.builder();

// Set the field 'year' to 2024
myObjBuilder.year(2024);

// Check the value of 'year' after building the object
console.log(myObjBuilder.build().year); // Outputs 2024

// Set the field 'year' to 2025 and build the object
myObjBuilder = myObjBuilder.year(2025);
console.log(myObjBuilder.build().year); // Outputs 2025

// Set the field 'year' to 2026 using the 'v' method and build the object
myObjBuilder.v("year", 2026);
console.log(myObjBuilder.build().year); // Outputs 2026

// Create the object and update its fields using the builder
let myObj = myObjBuilder.build();
myObj = myObj.toBuilder().year(2027).build();
console.log(myObj.year === 2027); // Outputs true

// Builders created from an Obj inherit the fields of the Obj
console.log(myObj.year); // Outputs 2027
Python
# Create a builder for Automobile
myObjBuilder = c3.Automobile.builder()

# Set the field 'year' to 2024
myObjBuilder.year(2024)

# Check the value of 'year' after building the object
print(myObjBuilder.build().year)  # Outputs 2024

# Set the field 'year' to 2025 and build the object
myObjBuilder = myObjBuilder.year(2025)
print(myObjBuilder.build().year)  # Outputs 2025

# Set the field 'year' to 2025 using the 'v' method and build the object
myObjBuilder.v("year", 2025)
print(myObjBuilder.build().year)  # Outputs 2025

# Create the object and update its fields using the builder
myObj = myObjBuilder.build()
myObj = myObj.toBuilder().year(2026).build()
print(myObj.year)  # Outputs 2026

Relationship between Types, meta-Types, and builders

The Collection Types, meta-Types, and builders form a cohesive pattern within the C3 Type System:

  1. Type: Represents the actual data structure with methods for common operations.
  2. Meta-Type: Defines the blueprint for the Type, ensuring consistency and providing factory methods.
  3. Builder: Allows for efficient and flexible construction and manipulation of the Type instances.

This pattern provides a clear separation of concerns, where the Type handles day-to-day operations, the meta-type defines the rules and structure, and the builder manages construction and batch modifications. This design allows developers to work with collections in a predictable and efficient manner, leveraging the strengths of each construct.

Working with Types, meta-Types, and builders

To create an empty C3 array, you need to specify the element Type of the array.

Here is an example of creating an empty C3 array of boolean:

JavaScript
// Create an empty C3 array of booleans
var arr = ArrayType.ofBool().emptyArray();
Python
# Create an empty C3 array of booleans
arr = c3.ArrayType.ofBool().emptyArray()

Convert an array to an indexed set in C3 DSL

JavaScript
// Convert an array to an indexed set
var arr_int = C3.Array.ofInt(1, 5, 4, 2, 2);
var indexed_set_from_arr = arr_int.toCollection(SetType.ofInt().index());
Python
# Convert an array to an indexed set
arr_int = c3.Array.ofInt(1, 5, 4, 2, 2)
indexed_set_from_arr = arr_int.toCollection(c3.SetType.ofInt().index())

You make a map or set that preserves insertion order by using the index method on CollectionType. For example, if you want a map of string to string that maintained insertion order, you can call the following:

JavaScript
// Create a map of string to string that maintains insertion order
var myMap = MapType.ofStrToStr().index().makeMap("key1", "value1", "key2", "value2");
Python
# Create a map of string to string that maintains insertion order
myMap = c3.MapType.ofStrToStr().index().makeMap("key1", "value1", "key2", "value2")

Now if you iterate through the keys of myMap, you would get them in order key1, then key2.

This example below demonstrates how to create and manipulate arrays of Automobile objects using methods from Array, ArrayType, and ArrayBuilder. It includes operations such as shuffling, union, mapping, and creating patterns.

Type
// Automobile.c3typ
type Automobile {
    model: string
    year: int
    color: string
    manufacturer: Manufacturer
    automobileCategory: AutomobileCategory
    maintenanceRecords: [MaintenanceRecord]
    price: double
}
JavaScript
// Create some Automobile instances
var porscheAuto = Automobile.make({
    model: "Porsche Taycan",
    year: 2024,
    color: "white",
    manufacturer: Manufacturer.make({name: "Porsche AG"}),
    automobileCategory: AutomobileCategory.SPORT_CAR,
    maintenanceRecords: [
        MaintenanceRecord.make({description: "Faulty battery!"}),
        MaintenanceRecord.make({description: "Tire alignment!"})
    ],
    price: 150000
});

var teslaAuto = Automobile.make({
    model: "Tesla X",
    year: 2024,
    color: "red",
    manufacturer: Manufacturer.make({name: "Tesla, Inc"}),
    automobileCategory: AutomobileCategory.SUV,
    maintenanceRecords: [
        MaintenanceRecord.make({description: "Battery replacement!"}),
        MaintenanceRecord.make({description: "Software update!"})
    ],
    price: 120000
});

// Use ArrayType to build a new array of Automobiles
var automobileArrayType = ArrayType.ofAny(Automobile);
var newAutomobiles = automobileArrayType.buildArray(function (builder) {
    builder.push(porscheAuto);
    builder.push(teslaAuto);
    return builder;
});

// Use ArrayBuilder to manipulate the Array
var arrayBuilder = newAutomobiles.toBuilder();
arrayBuilder.push(Automobile.make({
    model: "Ford Mustang",
    year: 2023,
    color: "blue",
    manufacturer: Manufacturer.make({name: "Ford Motor Company"}),
    automobileCategory: AutomobileCategory.SPORT_CAR,
    maintenanceRecords: [],
    price: 80000
}));

arrayBuilder.current().forEach(auto => {
    console.log(auto.memberMethod())
});

// Remove an automobile at a specific index
arrayBuilder.removeAt(0);

// Add an automobile at a specific index
arrayBuilder.insertAt(0, porscheAuto);

// Replace an automobile at a specific index
arrayBuilder.replaceAt(1, teslaAuto);

// Build the final Array
var finalAutomobiles = arrayBuilder.build();

// Shuffle the array
var shuffledAutomobiles = finalAutomobiles.shuffle();

// Union with another array
var unionAutomobiles = C3.Array.union(shuffledAutomobiles);

var mappedAutomobiles = finalAutomobiles.map(function (auto) {
    return auto.model + " - " + auto.year;
}); // Map to a new array of strings
console.log(`mappedAutomobiles: ${mappedAutomobiles}`)

// Creating a pattern of double prices
var pricePattern = C3.Array.patternOfDbl(unionAutomobiles.size, function (n) {
    return unionAutomobiles[n].price;
});
console.log(pricePattern); // Output the pattern of prices

// Using withSplice to modify the array
var splicedAutomobiles = finalAutomobiles.withSplice(1, 1, Automobile.make({
    model: "BMW i8",
    year: 2023,
    color: "black",
    manufacturer: Manufacturer.make({name: "BMW"}),
    automobileCategory: AutomobileCategory.SPORT_CAR,
    maintenanceRecords: [],
    price: 140000
}));
console.log(splicedAutomobiles); // Output the modified array

The following Python code demonstrates how to create and manipulate arrays of Automobile objects using methods from Array, ArrayType, and ArrayBuilder. It includes operations such as shuffling, union, mapping, and creating patterns.

Python
# Create some Automobile instances
porsche_auto = c3.Automobile(
    model="Porsche Taycan",
    year=2024,
    color="white",
    manufacturer=c3.Manufacturer(name="Porsche AG"),
    automobileCategory=c3.AutomobileCategory.SPORT_CAR,
    maintenanceRecords=[
        c3.MaintenanceRecord(description="Faulty battery!"),
        c3.MaintenanceRecord(description="Tire alignment!")
    ],
    price=150000
)

tesla_auto = c3.Automobile(
    model="Tesla X",
    year=2024,
    color="red",
    manufacturer=c3.Manufacturer(name="Tesla, Inc"),
    automobileCategory=c3.AutomobileCategory.SUV,
    maintenanceRecords=[
        c3.MaintenanceRecord(description="Battery replacement!"),
        c3.MaintenanceRecord(description="Software update!")
    ],
    price=120000
)

# Create an Array of Automobiles
automobiles = c3.Array.ofObj(porsche_auto, tesla_auto)

automobiles.toJson()

# Use ArrayBuilder to manipulate the Array
array_builder = automobiles.toBuilder()

array_builder.push(c3.Automobile(
    model="Ford Mustang",
    year=2023,
    color="blue",
    manufacturer=c3.Manufacturer(name="Ford Motor Company"),
    automobileCategory=c3.AutomobileCategory.SPORT_CAR,
    maintenanceRecords=[],
    price=80000
))

array_builder.current().toJson()

'''
[{'model': 'Porsche Taycan',
  'year': 2024,
  'color': 'white',
  'manufacturer': {'name': 'Porsche AG'},
  'automobileCategory': 'SPORT_CAR',
  'maintenanceRecords': [{'description': 'Faulty battery!'},
   {'description': 'Tire alignment!'}],
  'price': 150000.0},
 {'model': 'Tesla X',
  'year': 2024,
  'color': 'red',
  'manufacturer': {'name': 'Tesla, Inc'},
  'automobileCategory': 'SUV',
  'maintenanceRecords': [{'description': 'Battery replacement!'},
   {'description': 'Software update!'}],
  'price': 120000.0},
 {'model': 'Tesla X',
  'year': 2024,
  'color': 'red',
  'manufacturer': {'name': 'Tesla, Inc'},
  'automobileCategory': 'SUV',
  'maintenanceRecords': [{'description': 'Battery replacement!'},
   {'description': 'Software update!'}],
  'price': 120000.0},
 {'model': 'Ford Mustang',
  'year': 2023,
  'color': 'blue',
  'manufacturer': {'name': 'Ford Motor Company'},
  'automobileCategory': 'SPORT_CAR',
  'price': 80000.0}]
'''

array_builder.collectionType()

'''
{
  "type" : "ArrayType",
  "elementType" : {
    "type" : "ReferenceType",
    "name" : "Obj"
  }
}
'''

# Remove an automobile at a specific index
removed = array_builder.removeAt(0)

# Add an automobile at a specific index
inserted = array_builder.insertAt(0, porsche_auto)

# Replace an automobile at a specific index
replaced = array_builder.replaceAt(1, tesla_auto)

# Build the final Array
final_automobiles = array_builder.build()

# Advanced Array methods
shuffled_automobiles = final_automobiles.shuffle() # Shuffle the array
union_automobiles = final_automobiles.union(automobiles) # Union with another array
mapped_automobiles = final_automobiles.map(lambda auto: f"{auto.model} - {auto.year}") # Map to a new array of strings

# Using ArrayType's repeat method for a pattern
repeated_automobiles = c3.Array.pattern(c3.Automobile.meta().referenceType(), 5, lambda idx: porsche_auto if idx % 2 == 0 else tesla_auto)

repeated_automobiles.toJson()

# Using ArrayType's buildDbls method for an array of prices
# Function to build prices using lambda
def build_prices_with_lambda():
    builder = c3.Array.builderOfDbl()
    prices_lambda = lambda autos: [builder.push(auto.price) for auto in autos]
    prices_lambda(final_automobiles)
    return builder.build()

# Generate an array of double prices from the final_automobiles collection
prices = build_prices_with_lambda()

print(prices)

# Creating a pattern of double prices
price_pattern = c3.Array.patternOfDbl(5, lambda idx: 50000 if idx % 2 == 0 else 100000)
print(price_pattern) # Output the pattern of prices

# Using withSplice to modify the array
spliced_automobiles = automobiles.withSplice(1, 1, c3.Automobile(
    model="BMW i8",
    year=2023,
    color="black",
    manufacturer=c3.Manufacturer(name="BMW"),
    automobileCategory=c3.AutomobileCategory.SPORT_CAR,
    maintenanceRecords=[],
    price=140000
))
print(spliced_automobiles) # Output the modified array

This next example demonstrates the usage of Map, MapType, MapBuilder, Set, SetType, and SetBuilder. It includes operations such as manipulating maps and sets, using builders, and applying advanced methods like union, map, keys, and elements.

Maps in C3 represent collections of key-value pairs. Each key can appear only once in the collection, and you can store values associated with these keys. Maps are parameterized, meaning you define the types of keys and values they hold.

To create a map with string keys and integer values in JavaScript:

JavaScript
// Create an empty map with string keys and integer values
let inst = MapType.ofStrTo(PrimitiveType.ofInt()).emptyMap();
// Add an entry to the map
inst = inst.with("key", 1);
// Retrieve a value from the map
let value = inst.get("key");

To create a map with string keys and integer values in Python:

Python
# Create an empty map with string keys and integer values
inst = c3.MapType.ofStrTo(c3.PrimitiveType.ofInt()).emptyMap()

# Add an entry to the map
inst = inst.with_("key", 1)

# Retrieve a value from the map
value = inst.get("key")

C3 Set does not preserve the order in which you add elements. Instead, it maintains a sorted order, similar to most programming languages. When you convert a set to an array, the elements will appear in sorted order.

JavaScript
C3.Set.ofStr('b', 'c', 'a').toArray(ArrayType.ofStr())
Python
c3.Set.ofStr('b', 'c', 'a').toArray(c3.ArrayType.ofStr())

Create new Types if needed and integrate them into the existing code to demonstrate various advanced functions.

Additional Type definitions

Type
// Owner.c3typ
type Owner {
    name: string
    age: int
}

// Garage.c3typ
type Garage {
    name: string
    capacity: int
    automobiles: map<string, Automobile>
}

// Manufacturer.c3typ
type Manufacturer {
    name: string
}

// AutomobileCategory.c3typ
enum type AutomobileCategory {
    SPORT_CAR
    SEDAN
    SUV
    TRUCK
    EV
}

// MaintenanceRecord.c3typ
type MaintenanceRecord {
    description: string
}

Creating and manipulating maps and sets

The following example demonstrates how to create and manipulate maps and sets using methods from Map, MapType, MapBuilder, Set, SetType, and SetBuilder. It includes operations such as adding, removing, replacing elements, and using advanced methods like union, map, shuffle, and filter.

JavaScript
// Create some Owner instances
var owner1 = Owner.make({name: "Alice", age: 30});
var owner2 = Owner.make({name: "Bob", age: 45});

// Create a Map of Owners to their Automobiles
var ownerAutomobileMapBldr = MapType.ofStrTo(Automobile.meta().referenceType()).makeBuilder();
ownerAutomobileMapBldr.put(owner1.name, porscheAuto);
ownerAutomobileMapBldr.put(owner2.name, teslaAuto);

// Use MapBuilder to manipulate the Map
ownerAutomobileMapBldr.put("Charlie", Automobile.make({
    model: "Ford Mustang",
    year: 2023,
    color: "blue",
    manufacturer: Manufacturer.make({name: "Ford Motor Company"}),
    automobileCategory: AutomobileCategory.SPORT_CAR,
    maintenanceRecords: [],
    price: 80000
}));

// Remove an owner from the map
ownerAutomobileMapBldr.removeKey("Alice"); // true

// Replace an automobile for an owner
ownerAutomobileMapBldr.put("Bob", Automobile.make({
    model: "Chevrolet Camaro",
    year: 2023,
    color: "yellow",
    manufacturer: Manufacturer.make({name: "Chevrolet"}),
    automobileCategory: AutomobileCategory.SPORT_CAR,
    maintenanceRecords: [],
    price: 75000
}));

// Build the final Map
var finalOwnerAutomobileMap = ownerAutomobileMapBldr.build();

// Advanced Map methods
var keys = finalOwnerAutomobileMap.keys(); // Get all keys
var values = finalOwnerAutomobileMap.elements(); // Get all values

// Create a Set of Owners
var ownerSet = SetType.of(Owner.meta().referenceType()).makeSet(owner1, owner2)

// Use SetBuilder to manipulate the Set
var setBuilder = ownerSet.toBuilder();
setBuilder.add(Owner.make({name: "Charlie", age: 25}));
setBuilder.remove(owner1); // Remove an owner

// Build the final Set
var finalOwnerSet = setBuilder.build();

// Advanced Set methods
var uniqueOwners = finalOwnerSet.union(SetType.of(Owner.meta().referenceType()).makeSet(owner2)); // Union with another set
var mappedOwners = finalOwnerSet.map(function (owner) {
    return owner.name + " - " + owner.age;
}); // Map to a new set of strings

// Creating a Set of Automobiles
var automobileSet = SetType.of(Automobile.meta().referenceType()).makeSet(porscheAuto, teslaAuto);

// Using SetType to build a new set of Automobiles
var automobileSetType = SetType.of(Automobile.meta().referenceType());
var newAutomobileSet = automobileSetType.buildSet(function (builder) {
    builder.add(porscheAuto);
    builder.add(teslaAuto);
    return builder;
});

// Use SetBuilder to manipulate the Automobile Set
var autoSetBuilder = automobileSet.toBuilder();
autoSetBuilder.add(Automobile.make({
    model: "Ford Mustang",
    year: 2023,
    color: "blue",
    manufacturer: Manufacturer.make({name: "Ford Motor Company"}),
    automobileCategory: AutomobileCategory.SPORT_CAR,
    maintenanceRecords: [],
    price: 80000
}));

// Remove an automobile
autoSetBuilder.remove(porscheAuto);

// Build the final Set of Automobiles
var finalAutomobileSet = autoSetBuilder.build();

// Advanced Set methods for Automobiles
var filteredAutomobiles = finalAutomobileSet.filter(function (auto) {
    return auto.price > 100000
}); // Filter automobiles with price greater than 100000
var mappedAutomobileSet = finalAutomobileSet.map(function (auto) {
    return auto.model + " - " + auto.year;
}); // Map to a new set of strings

The following Python code demonstrates how to create and manipulate maps and sets using methods from Map, MapType, MapBuilder, Set, SetType, and SetBuilder. It includes operations such as adding, removing, replacing elements, and using advanced methods like union, map, shuffle, and filter.

Python
# Create some Owner instances
owner1 = c3.Owner(name="Alice", age=30)
owner2 = c3.Owner(name="Bob", age=45)

# Create a Map of Owners to their Automobiles
map_builder = c3.MapType.ofStrTo(c3.Automobile.meta().referenceType()).makeBuilder()
map_builder.put(owner1.name, porsche_auto)
map_builder.put(owner2.name, tesla_auto)
map_builder.isEmpty()
map_builder.size()
map_builder.current().get(owner1.name)

# Use MapBuilder to manipulate the Map
map_builder.put("Charlie", c3.Automobile(
    model="Ford Mustang",
    year=2023,
    color="blue",
    manufacturer=c3.Manufacturer(name="Ford Motor Company"),
    automobileCategory=c3.AutomobileCategory.SPORT_CAR,
    maintenanceRecords=[],
    price=80000
))

map_builder.current().get("Alice")
map_builder.current().get("Bob")
map_builder.current().get("Charlie")

# Remove an owner from the map
map_builder.removeKey("Alice")

# Replace an automobile for an owner
map_builder.put("Bob", c3.Automobile(
    model="Chevrolet Camaro",
    year=2023,
    color="yellow",
    manufacturer=c3.Manufacturer(name="Chevrolet"),
    automobileCategory=c3.AutomobileCategory.SPORT_CAR,
    maintenanceRecords=[],
    price=75000
))

# Build the final Map
final_owner_automobile_map = map_builder.build()

# Advanced Map methods
keys = final_owner_automobile_map.keys() # Get all keys
values = final_owner_automobile_map.elements() # Get all values

# Create a Set of Owners
owner_set = c3.Set.ofObj(owner1, owner2)

# Use SetBuilder to manipulate the Set
set_builder = c3.SetType.ofAny().makeBuilder()
set_builder.collectionType()
set_builder.add(c3.Owner(name="Charlie", age=25))

# Build the final Set
final_owner_set = set_builder.build()

# Advanced Set methods
# unique_owners = final_owner_set.union(c3.Set.of(owner2)) # Union with another set
unique_owners = c3.Set.union(c3.Set.ofAny(owner2)) 
mapped_owners = final_owner_set.map(lambda owner: f"{owner.name} - {owner.age}") # Map to a new set of strings

# Creating a Set of Automobiles
automobile_set = c3.Set.ofObj(porsche_auto, tesla_auto)

# Using SetType to build a new

# set of Automobiles
automobile_set_type = c3.SetType.of(c3.Automobile.meta().referenceType())
new_automobile_set = automobile_set_type.buildSet(lambda builder: builder.add(porsche_auto).add(tesla_auto))

# Use SetBuilder to manipulate the Automobile Set
automobile_set.add(c3.Automobile(
    model="Ford Mustang",
    year=2023,
    color="blue",
    manufacturer=c3.Manufacturer(name="Ford Motor Company"),
    automobileCategory=c3.AutomobileCategory.SPORT_CAR,
    maintenanceRecords=[],
    price=80000
))

# Advanced Set methods for Automobiles
filtered_automobiles = automobile_set.filter(lambda auto: auto.price > 100000) # Filter automobiles with price greater than 100000
mapped_automobile_set = automobile_set.map(lambda auto: f"{auto.model} - {auto.year}") # Map to a new set of strings

# Output results
print(final_owner_automobile_map)
print(keys)
print(values)
print(final_owner_set)
print(unique_owners)
print(mapped_automobile_set)

These Python and JavaScript snippets demonstrate creating and manipulating maps and sets using Map, MapType, MapBuilder, Set, SetType, and SetBuilder, including various advanced methods.

Was this page helpful?