英文:
Unpack / pack operator
问题
我正在寻找打包/解包运算符的不同实现方式。例如:
*[1,2,3] --> 1,2,3 (一个数组标量值解包为三个值)
*1,2,3 --> [1,2,3] (三个值打包为一个标量数组值)
这个运算符在各种编程语言中常见吗?如果是的话,通常是如何表示的?
其他可能的术语:
- 解构/构造
- 解包/打包
英文:
I'm looking to find various ways that a packing / unpacking operator is implemented. As an example:
*[1,2,3] --> 1,2,3 (one array scalar value unpacked to three values)
*1,2,3 --> [1,2,3] (three values packed to one scalar array value)
Is this a common operator in languages? If so, how is it usually represented?
Other possible terms:
- Destructuring / structuring
- Unpacking / packing
答案1
得分: 3
在不同编程语言中实现这一目标的方式各不相同。
在Python中,可以使用元组进行值的打包和解包:
mytuple = (1, 2, 3) # 打包为元组
(a, b, c) = mytuple # 解包
print(f'{a}, {b}, {c}')
在C++11中,可以使用 std::tie()
完成:
#include <iostream>
#include <tuple>
int main()
{
auto mytuple = std::tuple<int, int, int>{1, 2, 3}; // 打包为元组
int a, b, c;
std::tie(a, b, c) = mytuple; // 解包 (std::tie)
std::cout << a << " " << b << " " << c << std::endl;
return 0;
}
而在C++17及更新版本中,可以使用结构化绑定:
#include <iostream>
#include <tuple>
int main()
{
auto mytuple = std::tuple{1, 2, 3}; // 打包为元组
auto [a, b, c] = mytuple; // 解包 (结构化绑定)
std::cout << a << " " << b << " " << c << std::endl;
return 0;
}
英文:
The way to achieve this depends on the language.
In python values can be packed / unpacked using tuples:
mytuple = (1,2,3) # Packing into a tuple
(a,b,c) = mytuple # Unpacking
print(f'{a}, {b}, {c}')
In c++11, it can be done by using std::tie()
:
#include <iostream>
#include <tuple>
int main()
{
auto mytuple = std::tuple<int,int,int>{1,2,3}; // Packing into a tuple
int a, b, c;
std::tie(a,b,c) = mytuple; // Unpacking (std::tie)
std::cout << a << " " << b << " " << c << std::endl;
return 0;
}
And, in c++17 and newer, structured bindings can be used:
#include <iostream>
#include <tuple>
int main()
{
auto mytuple = std::tuple{1,2,3}; // Packing into a tuple
auto[a,b,c] = mytuple; // Unpacking (structured binding)
std::cout << a << " " << b << " " << c << std::endl;
return 0;
}
答案2
得分: 2
我将描述整个相关工作和Python中的语法。
将变量打包为集合并将可迭代对象解包到某些变量中:
iterable = (1, 2, 3, 4) # 通过元组显式打包
iterable = 1, 2, 3, 4 # 通过元组隐式打包
iterable = [1, 2, 3, 4] # 通过列表打包
nested_iterable = (1, 2, (4, 5, 6)) # 打包嵌套项目
mapping = {"a": 1, "b": 2}
a, b, c, d = iterable # 使用元组隐式解包
(a, b, c, d) = iterable # 使用元组显式解包
[a, b, c, d] = iterable # 使用列表解包
a, _, _, d = iterable # 通过传统使用 _(称为 Throwaway)变量忽略某些值
a, *middle_items, d = iterable # 使用 * 将其余项目分组为列表
a, b, c, *d = iterable # 对于单个元素也使用 *,将其分组为单个项目的列表
a, b, c, d, *e = iterable # 如果没有其他元素,则 e 变为空列表
a, *_ = iterable # 忽略剩余项
a, b, (c, d, e) = nested_iterable # 使用元组解包嵌套项
a, b, [c, d, e] = nested_iterable # 使用混合元组和列表解包嵌套项
a_key, b_key = mapping # 项目在解包时被迭代,因此只返回键
(a_key, a_value), (b_key, b_value) = mapping.items() # 使用 items 方法解包映射
注意:在单个解包中无法多次应用 *
运算符。
将可迭代对象解包为位置参数和映射解包为命名参数,同时打包剩余的位置和命名参数:
def normal_function(a, b, c, d):
...
items = [2, 3, 4, 5]
mapping = {"a": 2, "b": 3, "c": 4, "d": 5}
normal_function(*items) # 将位置解包到函数参数。
normal_function(**mapping) # 将命名解包到函数参数。
def variadic_function(a, b, c, *remaining_positional_args, d, e, f, **remaining_named_args):
# remaining_positional_args 是元组,remaining_named_args 是字典
# d、e、f 必须通过名称填充
...
英文:
I will describe the whole related works and syntax in Python.
Packing variables as a collection and unpacking iterables to some variables:
iterable = (1, 2, 3, 4) # Packing by Tuple explicitly
iterable = 1, 2, 3, 4 # Packing by Tuple implicitly
iterable = [1, 2, 3, 4] # Packing by List
nested_iterable = (1, 2, (4, 5, 6)) # Packing nested items
mapping = {"a": 1, "b": 2}
a, b, c, d = iterable # Unpacking using Tuple implicitly
(a, b, c, d) = iterable # Unpacking using Tuple explicitly
[a, b, c, d] = iterable # Unpacking using List
a, _, _, d = iterable # Ignoring some values by conventionally using the _ (called Throwaway) variable
a, *middle_items, d = iterable # Using * to group remaining items as a List
a, b, c, *d = iterable # Using * for a single element is also grouped as a single item List
a, b, c, d, *e = iterable # If there are no other elements, e becomes an empty List
a, *_ = iterable # Ignoring remaining items
a, b, (c, d, e) = nested_iterable # Unpacking nested items using Tuple
a, b, [c, d, e] = nested_iterable # Unpacking nested items using mixed Tuple and List
a_key, b_key = mapping # The items get iterated for unpacking, so, here, only keys got returned
(a_key, a_value), (b_key, b_value) = mapping.items() # Unpacking a mapping using items method
Note: You cannot apply the *
operator multiple times in a single unpacking.
Unpacking iterables as positional arguments and mappings as named arguments along with Packing remaining positional and named arguments:
def normal_function(a, b, c, d):
...
items = [2, 3, 4, 5]
mapping = {"a": 2, "b": 3, "c": 4, "d": 5}
normal_function(*items) # Positional unpacking to function arguments.
normal_function(**mapping) # Named unpacking to function arguments.
def variadic_function(a, b, c, *remaining_positional_args, d, e, f, **remaining_named_args):
# remaining_positional_args is a Tuple and remaining_named_args is a Dict
# d, e, f must be filled by the name
...
答案3
得分: 1
Packing and unpacking, also known as destructuring and structuring, is a common concept in many programming languages. It allows for the assignment of multiple values to multiple variables in a single statement, or for the passing of multiple values as arguments to a function.
In C++, you can use structured bindings (since C++17) to unpack the elements of an array or tuple into separate variables:
#include <array>
#include <iostream>
#include <tuple>
int main() {
std::array<int, 3> myarray = {1, 2, 3};
auto [a, b, c] = myarray;
std::cout << a << ' ' << b << ' ' << c << '\n'; // prints 1 2 3
std::tuple<int, int, int> mytuple = {4, 5, 6};
auto [x, y, z] = mytuple;
std::cout << x << ' ' << y << ' ' << z << '\n'; // prints 4 5 6
}
In JavaScript, the spread operator (…) is used for unpacking. It works similarly to the asterisk operator in Python:
function myfunc(a, b, c) {
console.log(a, b, c);
}
let myarray = [1, 2, 3];
myfunc(...myarray); // prints 1 2 3
In Python, the asterisk (*) operator is used for unpacking. For example, you can use it to unpack the elements of a list or tuple and pass them as separate arguments to a function:
def myfunc(a, b, c):
print(a, b, c)
mylist = [1, 2, 3]
myfunc(*mylist) # prints 1 2 3
The syntax and behavior may vary depending on the language and its version.
英文:
Packing and unpacking, also known as destructuring and structuring, is a common concept in many programming languages. It allows for the assignment of multiple values to multiple variables in a single statement, or for the passing of multiple values as arguments to a function.
In C++, you can use structured bindings (since C++17) to unpack the elements of an array or tuple into separate variables:
#include <array>
#include <iostream>
#include <tuple>
int main() {
std::array<int, 3> myarray = {1, 2, 3};
auto [a, b, c] = myarray;
std::cout << a << ' ' << b << ' ' << c << '\n'; // prints 1 2 3
std::tuple<int, int, int> mytuple = {4, 5, 6};
auto [x, y, z] = mytuple;
std::cout << x << ' ' << y << ' ' << z << '\n'; // prints 4 5 6
}
In JavaScript, the spread operator (…) is used for unpacking. It works similarly to the asterisk operator in Python:
function myfunc(a, b, c) {
console.log(a, b, c);
}
let myarray = [1, 2, 3];
myfunc(...myarray); // prints 1 2 3
In Python, the asterisk (*) operator is used for unpacking. For example, you can use it to unpack the elements of a list or tuple and pass them as separate arguments to a function:
def myfunc(a, b, c):
print(a, b, c)
mylist = [1, 2, 3]
myfunc(*mylist) # prints 1 2 3
> The syntax and behavior may vary depending on the language and its version
答案4
得分: 1
你提到了数组,但打包和解包只是指在将整个包传递给函数之前,分别将多个实体制作成一个包束,以及将包束的组成部分作为单独的参数传递给函数。
包束实际上是什么(数组、元组、结构体)在某种程度上是一个实现细节,只要你有一种方法可以从组成部分创建一个包束,并且有一种方法可以从一个包束中提取组成部分。
在C++中,std::tuple
是首选,因为它让你在实体的数量和类型上都有自由度,而std::array
将限制你必须使用相同的类型来处理所有实体,因此在大多数情况下不适用。
所以当你想要在将更多实体打包在一起然后传递给函数时,你只需使用std::make_tuple
。
对于解包,情况更复杂,但幸运的是有一些现成的库解决方案:Boost.Hana 提供了 boost::hana::unpack
,它允许你做类似于以下的事情:
constexpr auto add = [](auto x, auto y, auto z) {
return x + y + z;
};
std::cout << hana::unpack(hana::make_tuple(1, 2, 3), add); // 输出 6
(这个示例使用了 boost::hana::tuple
,但很容易扩展 Hana 以使 hana::unpack
适用于 std::tuple
。)
在这方面,std::tie
和结构化绑定有点像最基本的构建块,因为它们允许你在将它们传递给所需的函数之前为各个实体命名。与上面的示例相比,你可以将其重写为:
constexpr auto add = [](auto x, auto y, auto z) {
return x + y + z;
};
auto const& [a, b, c] = std::make_tuple(1, 2, 3);
std::cout << add(a, b, c); // 输出 6
这有点繁琐,因为你必须为可能在特定情况下实际上没有太多意义的名称发明名字;同样明显的是,如果元组只是一组无关的事物,将采用无关的代码路径,那么也许结构化绑定更有意义。
在其他语言中,打包和解包更加简单。以 JavaScript 为例,其中数组可以是异构的;打包更多的东西只是将它们包含在 [
和 ]
中的 ,
分隔列表中。对于解包,有 ...
运算符。以下是与上面使用完整库的 C++ 代码对应的原生 JavaScript 代码:
add = x => x[0] + x[1] + x[2]
console.log(add([1, 2, 3])) // 输出 6
add = (x, y, z) => x + y + z;
console.log(add(...[1, 2, 3])) // 输出 6
最后,在像 Haskell 这样的语言中,函数都是柯里化的,即它们逐个接受参数,打包和解包基本上与柯里化和非柯里化一致:
add3'curried = \x y z -> x + y + z -- === curry3 add3'uncurried
triple = (1, 2, 3)
uncurry3 add3'curried $ triple -- 输出 6
add3'uncurried = \(x, y, z) -> x + y + z -- === uncurry3 add3'curried
curry3 add3'uncurried 1 2 3 -- 输出 6
英文:
You mention array, but packing and unpacking just mean, respectively, making 1 boundle out of multiple entities before passing the whole bundle to a function, and passing the constituents of a bundle as separate arguemnts to a function.
What the bundle actualy is (an array, a tuple, a struct) is kind of an implementation detail, as long as you have a way to create one out of the constituensts, and a way to pull the constituents out of one.
In C++, a std::tuple
is preferrable, because that gives you freedom on both the number and the types of entities you can bundle together. A std::array
would restrict you to use the same type for all entities, so it's out of question in most scenarii.
So when you want to pack together more entities before passing them to a function, you just use std::make_tuple
.
For unpacking, the situation is more complex, but luckly there's some ready-to-use library solution: Boost.Hana offers boost::hana::unpack
, which allows you to do something like this
constexpr auto add = [](auto x, auto y, auto z) {
return x + y + z;
};
std::cout << hana::unpack(hana::make_tuple(1, 2, 3), add); // prints 6
(The example uses boost::hana::tuple
, but it's easy to extend Hana to make hana::unpack
work for std::tuple
s as well.)
In this respect, std::tie
and structured bindings are kind of the minimal building blocks, because they allow you to give names to the individual entities before you pass them to the desired function. With reference to the example above, you could rewrite it as
constexpr auto add = [](auto x, auto y, auto z) {
return x + y + z;
};
auto const& [a, b, c] = std::make_tuple(1, 2, 3);
std::cout << add(a, b, c); // prints 6
which is bit more cumbersome, because you have to invent name that might not actually make much sense, depending on the specific case, clearly; as much clearly, if the tuple is just a collection of unrelated things which will take unrelated code paths, then maybe structured binding makes more sense.
In other languages packing and unpacking is more straightforward. Take JavaScript, where arrays can be etherogenous; packing more things just means enclosing them in a ,
-separated list inside [
and ]
. For unpacking, there's the ...
operator. Here's native JavaScript code that corresponds to the C++ code above which uses a full-fledge libarary:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
add = x => x[0] + x[1] + x[2]
console.log(add([1, 2, 3])) // prints 6
add = (x, y, z) => x + y + z;
console.log(add(...[1, 2, 3])) // prints 6
<!-- end snippet -->
Finally, in a language like Haskell, where functions are all curried, i.e. they accept arguments one by one, packing and unpacking fundamentally coincide with uncurrying and currying respectively:
add3'curried = \x y z -> x + y + z -- === curry3 add3'uncurried
triple = (1, 2, 3)
uncurry3 add3'curried $ triple -- prints 6
add3'uncurried = \(x, y, z) -> x + y + z -- === uncurry3 add3'curried
curry3 add3'uncurried 1 2 3 -- prints 6
答案5
得分: 0
以下是如何在不同的编程语言中实现数组解构和结构:
JavaScript(js)
解构:
const [a, b, c] = [1, 2, 3]; // 将数组解构为单独的变量a、b和c
结构:
const packedArray = [a, b, c]; // 将值打包到一个新数组中
Python(py)
解构:
a, b, c = (1, 2, 3) # 将元组解构为单独的变量a、b和c
结构:
packed_tuple = (a, b, c) # 将值打包到一个新元组中
C++(cpp)
C++没有像JavaScript或Python那样的直接内置机制来进行数组解构或结构。然而,你可以使用以下方法实现类似的效果:
解构:
你可以手动将数组的值分配给单独的变量。
int arr[] = {1, 2, 3};
int a = arr[0];
int b = arr[1];
int c = arr[2];
结构:
你可以创建一个数组或数据结构来保存这些值。
int a = 1;
int b = 2;
int c = 3;
int arr[] = {a, b, c};
英文:
Here's how array destructuring and structuring might be implemented in different languages:
js
Destructuring:
const [a, b, c] = [1, 2, 3]; // Unpacks the array into individual variables a, b, and c
Structuring:
const packedArray = [a, b, c]; // Packs the values into a new array
py
Destructuring:
a, b, c = (1, 2, 3) # Unpacks the tuple into individual variables a, b, and c
Structuring:
packed_tuple = (a, b, c) # Packs the values into a new tuple
cpp
C++ doesn't have a direct built-in mechanism for array destructuring or structuring like JavaScript or Python. However, you can achieve similar results using the following approaches:
Destructuring:
You can manually assign values from an array to individual variables.
int arr[] = {1, 2, 3};
int a = arr[0];
int b = arr[1];
int c = arr[2];
Structuring:
You can create an array or a data structure to hold the values.
int a = 1;
int b = 2;
int c = 3;
int arr[] = {a, b, c};
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论