how to define a custom subscripting array operator which makes array elements spring into existence if necessary
This isn’t related to the subscript operator, but more a question of how to define a ??=
operator. Which you can do, but it might not work quite the way you expect.
Here’s a possible implementation:
// first define the ??= operator
infix operator ??= { }
// then some pretty standard logic for an assignment
// version of ??
func ??=<T>(inout lhs: T?, rhs: T) {
lhs = lhs ?? rhs
}
This compiles, and works as you might be expecting:
var i: Int? = 1
i ??= 2 // i unchanged
var j: Int? = nil
j ??= 2 // j is now Some(2)
It will also work in combination with subscripts:
var a: [Int?] = [1, nil]
a[1] ??= 2
a[1] // is now Some(2)
I say this might not work completely as expected because of the types. a ?? b
takes an optional a
, and if it’s nil
, returns a default of b
. However it returns a non-optional value. That’s kinda the point of ??
.
On the other hand, ??=
cannot do this. Because the left-hand side is already determined to be optional, and an assignment operator cannot change the type only the value. So while it will substitute the value inside the optional in the case of nil
, it won’t change the type to be non-optional.
PS the reason the ??=
function compiles at all is because non-optional values (i.e. what you will get back from lhs ?? rhs
) are implicitly upgraded to optional values if necessary, hence lhs ?? rhs
, of type T
, can be assigned to lhs
, which is of type T?
.
PHP: Access Array Value on the Fly
I wouldn't bother about that extra variable, really. If you want, though, you could also remove it from memory after you've used it:
$variable = array('a','b','c');
echo $variable[$key];
unset($variable);
Or, you could write a small function:
function indexonce(&$ar, $index) {
return $ar[$index];
}
and call this with:
$something = indexonce(array('a', 'b', 'c'), 2);
The array should be destroyed automatically now.
Why array type object is not modifiable?
Assume the declaration
int a[10];
then all of the following are true:
- the type of the expression
a
is "10-element array ofint
"; except whena
is the operand of thesizeof
or unary&
operators, the expression will be converted to an expression of type "pointer toint
" and its value will be the address of the first element in the array; - the type of the expression
a[i]
isint
; it refers to the integer object stored as thei
'th element of the array; - The expression
a
may not be the target of an assignment because C does not treat arrays like other variables, so you cannot write something likea = b
ora = malloc(n * sizeof *a)
or anything like that.
You'll notice I keep emphasizing the word "expression". There's a difference between the chunk of memory we set aside to hold 10 integers and the symbols (expressions) we use to refer to that chunk of memory. We can refer to it with the expression a
. We can also create a pointer to that array:
int (*ptr)[10] = &a;
The expression *ptr
also has type "10-element array of int
", and it refers to the same chunk of memory that a
refers to.
C does not treat array expressions (a
, *ptr
) like expressions of other types, and one of the differences is that an expression of array type may not be the target of an assignment. You cannot reassign a
to refer to a different array object (same for the expression *ptr
). You may assign a new value to a[i]
or (*ptr)[i]
(change the value of each array element), and you may assign ptr
to point to a different array:
int b[10], c[10];
.....
ptr = &b;
.....
ptr = &c;
As for the second question...
An incomplete type lacks size information; declarations like
struct foo;
int bar[];
union bletch;
all create incomplete types because there isn't enough information for the compiler to determine how much storage to set aside for an object of that type. You cannot create objects of incomplete type; for example, you cannot declare
struct foo myFoo;
unless you complete the definition for struct foo
. However, you can create pointers to incomplete types; for example, you could declare
struct foo *myFooPtr;
without completing the definition for struct foo
because a pointer just stores the address of the object, and you don't need to know the type's size for that. This makes it possible to define self-referential types like
struct node {
T key; // for any type T
Q val; // for any type Q
struct node *left;
struct node *right;
};
The type definition for struct node
isn't complete until we hit that closing }
. Since we can declare a pointer to an incomplete type, we're okay. However, we could not define the struct as
struct node {
... // same as above
struct node left;
struct node right;
};
because the type isn't complete when we declare the left
and right
members, and also because each left
and right
member would each contain left
and right
members of their own, each of which would contain left
and right
members of their own, and on and on and on.
That's great for structs and unions, but what about
int bar[];
???
We've declared the symbol bar
and indicated that it will be an array type, but the size is unknown at this point. Eventually we'll have to define it with a size, but this way the symbol can be used in contexts where the array size isn't meaningful or necessary. Don't have a good, non-contrived example off the top of my head to illustrate this, though.
EDIT
Responding to the comments here, since there isn't going to be room in the comments section for what I want to write (I'm in a verbose mood this evening). You asked:
Does it mean every variables are expression?
It means that any variable can be an expression, or part of an expression. Here's how the language standard defines the term expression:
6.5 Expressions
1 An expression is a sequence of operators and operands that specifies computation of a
value, or that designates an object or a function, or that generates side effects, or that
performs a combination thereof.
For example, the variable a
all by itself counts as an expression; it designates the array object we defined to hold 10 integer values. It also evaluates to the address of the first element of the array. The variable a
can also be part of a larger expression like a[i]
; the operator is the subscript operator []
and the operands are the variables a
and i
. This expression designates a single member of the array, and it evaluates to the value currectly stored in that member. That expression in turn can be part of a larger expression like a[i] = 0
.
And also let me clear that, in the declaration int a[10], does a[] stands for array type
Yes, exactly.
In C, declarations are based on the types of expressions, rather than the types of objects. If you have a simple variable named y
that stores an int
value, and you want to access that value, you simply use y
in an expression, like
x = y;
The type of the expression y
is int
, so the declaration of y
is written
int y;
If, on the other hand, you have an array of int
values, and you want to access a specific element, you would use the array name and an index along with the subscript operator to access that value, like
x = a[i];
The type of the expression a[i]
is int
, so the declaration of the array is written as
int arr[N]; // for some value N.
The "int
-ness" of arr
is given by the type specifier int
; the "array-ness" of arr
is given by the declarator arr[N]
. The declarator gives us the name of the object being declared (arr
) along with some additional type information not given by the type specifier ("is an N-element array"). The declaration "reads" as
a -- a
a[N] -- is an N-element array
int a[N]; -- of int
EDIT2
And after all that, I still haven't told you the real reason why array expressions are non-modifiable lvalues. So here's yet another chapter to this book of an answer.
C didn't spring fully formed from the mind of Dennis Ritchie; it was derived from an earlier language known as B (which was derived from BCPL).1 B was a "typeless" language; it didn't have different types for integers, floats, text, records, etc. Instead, everything was simply a fixed length word or "cell" (essentially an unsigned integer). Memory was treated as a linear array of cells. When you allocated an array in B, such as
auto V[10];
the compiler allocated 11 cells; 10 contiguous cells for the array itself, plus a cell that was bound to V containing the location of the first cell:
+----+
V: | | -----+
+----+ |
... |
+----+ |
| | <----+
+----+
| |
+----+
| |
+----+
| |
+----+
...
When Ritchie was adding struct
types to C, he realized that this arrangement was causing him some problems. For example, he wanted to create a struct type to represent an entry in a file or directory table:
struct {
int inumber;
char name[14];
};
He wanted the structure to not just describe the entry in an abstract manner, but also to represent the bits in the actual file table entry, which didn't have an extra cell or word to store the location of the first element in the array. So he got rid of it - instead of setting aside a separate location to store the address of the first element, he wrote C such that the address of the first element would be computed when the array expression was evaluated.
This is why you can't do something like
int a[N], b[N];
a = b;
because both a
and b
evaluate to pointer values in that context; it's equivalent to writing 3 = 4
. There's nothing in memory that actually stores the address of the first element in the array; the compiler simply computes it during the translation phase.
1. This is all taken from the paper The Development of the C Language
Array of Objects in Spring Boot REST API
Take a look at the following:
Whenever I add a single object to an array, it replaces all the objects that were previously in the array. For instance, I have two objects in the "Spring 2020" array. If I make another POST request with addCourse(), both the objects get replaced.
The problem is that you are using map.put()
. When using this method, if the map previously contained a mapping for the key, the old value is replaced by the specified value. Hence, your old values are removed.
The solution is to get and update the existing entry.
public void add( Map<String, List<Courses>> course) {
course.forEach((semester, list) -> {
if(courseList.contains(semester)) {
courseList.get(semester).addAll(list); // Note, list accepts duplicates
} else {
courseList.put(semester, list);
}
});
}
If I try to edit using postman, I get some exception.
PUT: localhost:8080/edit/Spring20/
"message": "Missing URI template variable 'semester' for method parameter of type String",
The problem is that your path variable name semester does not match the name in the url semster. Hence, Missing URI template variable 'semester'
@RequestMapping(method=RequestMethod.PUT, value="/edit/{semester}/{id}")
public void addCourse(@PathVariable("semester") String semester, @PathVariable("id") String id, @RequestBody Courses course) {
service.editTest(semester, course);
}
Spring Data Mongo Template - Counting an array
It's quite possible, the $size
operator is supported (see DATAMONGO-979 and its implementation here). Your implementation could follow this example:
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;
Aggregation agg = new Aggregation(
match(where("_id").is("1")), //
project() //
.and("array") //
.size() //
.as("count")
);
AggregationResults<IntegerCount> results = mongoTemplate.aggregate(
agg, collectionName, Integer.class
);
List<IntegerCount> intCount = results.getMappedResults();
Related Topics
How to Conform an Observableobject to the Codable Protocols
How to Change the Colour of Separator in List of Swiftui
Swift 3: Safe Way to Decode Values with Nscoder
How to Fix Error: Abort Trap 6 (In Target 'Realmswift' from Project 'Pods')
Swift Change the Tableviewcell Border Color According to Data
How to Change Text Color of Actionsheet in Swiftui
Avoid Automatic Framework Linking in Swift
Xcode 11 - Disable Resize Mode in Catalyst Swift
Toggle Sidebar in Swiftui Navigationview on MACos
Swift/Cloudkit: After Record Changed, Upload Triggers "Service Record Changed"
How to Make a Segue to Second Item of Tab Bar
Swiftui Navigation: How to Switch Detail View to a Different Item
Get Current Url from Browser in MACos
Maccatalyst App: How to Close a Window Without Terminating The App