如何执行多个数组过滤

huangapple go评论61阅读模式
英文:

How to perform multiple array filtering

问题

我有两个数组,它们具有相互的ID,所以我可以将它们连接在一起,但我需要帮助进行过滤。

因此,我有第一个数组的列表,并在其前面有复选框。
如果我选择一个复选框,我会执行过滤操作,并在表格中显示第二个数组中的另一个项目(通过检查相互的ID)。

我需要帮助,因为如果我执行多次选择,我期望有多个结果,而不仅仅是一个。这是它的外观以及我用于过滤的代码。

所以如果我选择项目1和项目2的复选框,我期望从apps数组中得到3个结果(ids 10,20(x2))在下面的表格中。
当然,如果我取消选择复选框,它们应该从下面的表格中删除。因为我只使用.filter方法,我只能获得一个结果(来自最后选择的复选框)。

  let items = [
    {id:1, name:'Item 1', appId:10},
    {id:2, name:'Item 2', appId:20},
    {id:3, name:'Item 3', appId:20},
    {id:4, name:'Item 4', appId:30}
  ]
  
  let apps = [
    {id:10, address:'Some street 1', city:'City 1'},
    {id:20, address:'Some street 2', city:'City 2'},
    {id:20, address:'Some street 2', city:'City 2'},
    {id:30, address:'Some street 3', city:'City 3'}
  ]

this.dataSource = this.items.filter(x => x.appId == apps.id)

谢谢

更新

我已经按照Rohit的答案做到了,但现在我有一个问题,因为当我在第一个数组中选择复选框时,所有先前在第二个数组中选择的复选框都被删除了,所以问题是如何保留它们?

我已经添加了新的图像,之前和之后,所以在选择Item 1的复选框之后,我希望Some street 9和Some street 10的复选框仍然被选中。

我的HTML。

<table mat-table [dataSource]="dataSourceObjects" class="mat-elevation-z8">
  <ng-container matColumnDef="objectChBox">
    <th mat-header-cell *matHeaderCellDef></th>
    <td mat-cell *matCellDef="let element">
      <mat-checkbox
        class=""
        [checked]="element.chbxActive"
        (change)="checkSingleObject($event, element)"
      >
      </mat-checkbox>
    </td>
  </ng-container>

  <ng-container matColumnDef="address">
    <th mat-header-cell *matHeaderCellDef>Address</th>
    <td mat-cell *matCellDef="let element">{{element.address}}</td>
  </ng-container>

  <ng-container matColumnDef="city">
    <th mat-header-cell *matHeaderCellDef>City</th>
    <td mat-cell *matCellDef="let element">{{element.city}}</td>
  </ng-container>

  <tr mat-header-row *matHeaderRowDef="displayedColumnsObjects"></tr>
  <tr mat-row *matRowDef="let row; columns: displayedColumnsObjects;"></tr>
</table>

如何执行多个数组过滤
[![after][3]][3]


如果您需要进一步的帮助,请告诉我。

<details>
<summary>英文:</summary>

I have two arrays which have mutual ID, so I am able to connect them together but I need help with filtering.

So I have a list of first array and check box in front of it.
If I select one check box, I am performing filtering and I am displaying another item from second array inside the table (by checking up the mutual ID).

I need help because if I perform multiple selection, I expect to have multiple results, and not just one. This is the image how it looks like and the code I am using for filtering.

So if I select check box for Item 1 and Item 2 I expect to have 3 results (ids 10, 20(x2)) from apps array in the lower table.
Of course if I deselect check box, they should be removed from the lower table. Because I am using only .filter method, I am able to get only one result (from last selected checkbox).

let items = [
{id:1, name:'Item 1', appId:10},
{id:2, name:'Item 2', appId:20},
{id:3, name:'Item 3', appId:20},
{id:4, name:'Item 4', appId:30}
]

let apps = [
{id:10, address:'Some street 1', city:'City 1'},
{id:20, address:'Some street 2', city:'City 2'},
{id:20, address:'Some street 2', city:'City 2'},
{id:30, address:'Some street 3', city:'City 3'}
]

this.dataSource = this.items.filter(x => x.appId == apps.id)

[![enter image description here][1]][1]

Thanks


**UPDATE**

I have managed to do it by Rohit&#39;s answer, but I have a problem now because when I select check box in first array, all previously selected check boxes in second array are being removed, so the question is how to keep them?

I have added new images, before and after, so after selecting check box Item 1, I expect check boxes for Some street 9 and Some street 10 to remain selected.

My html.

<table mat-table [dataSource]="dataSourceObjects" class="mat-elevation-z8">
<ng-container matColumnDef="objectChBox">
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *matCellDef="let element">
<mat-checkbox
class=""
[checked]="element.chbxActive"
(change)="checkSingleObject($event, element)"
>
</mat-checkbox>
</td>
</ng-container>

<ng-container matColumnDef="address">
<th mat-header-cell *matHeaderCellDef>Address</th>
<td mat-cell *matCellDef="let element">{{element.address}}</td>
</ng-container>

<ng-container matColumnDef="city">
<th mat-header-cell *matHeaderCellDef>City</th>
<td mat-cell *matCellDef="let element">{{element.city}}</td>
</ng-container>

<tr mat-header-row *matHeaderRowDef="displayedColumnsObjects"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumnsObjects;"></tr>
</table>


[![before][2]][2]
[![after][3]][3]


  [1]: https://i.stack.imgur.com/4OpRR.png
  [2]: https://i.stack.imgur.com/2SOeX.png
  [3]: https://i.stack.imgur.com/gKLXW.png

</details>


# 答案1
**得分**: 3

根据您当前的实现,由于`apps`是一个数组,其项目应通过`索引`访问,不能直接使用点(.)符号访问。

由于用户可以选择多个项目,我们可以根据从`items`数组中选择的`appId`在`apps`数组中检查`id`。

仅用于演示目的,我直接将`appId` 10和20分配给一个数组,然后将使用[`Array#filter`][1]方法以及[`Array#includes`][2]方法从`apps`数组中获取映射结果。

```javascript
// Apps数组
let apps = [
  {id:10, address:'Some street 1', city:'City 1'},
  {id:20, address:'Some street 2', city:'City 2'},
  {id:20, address:'Some street 2', city:'City 2'},
  {id:30, address:'Some street 3', city:'City 3'}
];

// 选定的项目数组。
const selectedItems = [10, 20];

const result = apps.filter(({ id }) => selectedItems.includes(id));

// 结果
console.log(result);

更新: 根据作者的要求,以下是完整的工作演示(在下面的代码段中已添加了描述性注释)。

// 输入数组1
let items = [
  {id:1, name:'Item 1', appId:10},
  {id:2, name:'Item 2', appId:20},
  {id:3, name:'Item 3', appId:20},
  {id:4, name:'Item 4', appId:30}
];

// 输入数组2
const apps = [
  {id:10, address:'Some street 1', city:'City 1'},
  {id:20, address:'Some street 2', city:'City 2'},
  {id:30, address:'Some street 3', city:'City 3'}
];

// 复选框将绑定到的元素。
var myDiv = document.getElementById("checkBoxes");

// 循环遍历“items”数组中的每个对象,动态创建复选框并绑定到引用“checkBoxes”元素的“myDiv”变量。
for (var i = 0; i < items.length; i++) {
  var checkBox = document.createElement("input");
  var label = document.createElement("label");
  checkBox.type = "checkbox";
  checkBox.value = items[i].appId;
  myDiv.appendChild(checkBox);
  myDiv.appendChild(label);
  label.appendChild(document.createTextNode(items[i].name));
}

// 获取所有复选框元素以进行迭代。
var cbs = document.querySelectorAll('input[type="checkbox"]');

// 此变量将保存选定的复选框值。
let selectedItems = [];

// 迭代每个复选框元素并触发“onchange”事件。
cbs.forEach(function(item) {
  item.onchange = getCheckBoxValue;
});

// 负责将所有选定的复选框值获取到一个数组中的方法。
function getCheckBoxValue() {
  selectedItems = [];
  cbs.forEach(function(item) {
    if (item.checked) {
      if (!selectedItems.includes(item.value)) {
      	selectedItems.push(item.value);
      }
    }
  });
  getFilteredValuesFromAnotherArr();
}

// 最终的方法,基本上用于根据第一个数组的选择从第二个数组中获取选定的值。
function getFilteredValuesFromAnotherArr() {
  console.log(apps.filter(({ id }) => selectedItems.includes(id.toString()));
}
英文:

Observation as per your current implementation, As apps is an array. It's items should be access via index, we can not directly access using dot(.) notation.

As user can select multiple items, we can just check for the id in the apps array based on the appId selected from the items array using checkbox.

Just for a demo purpose, I am directly assigning the appId 10 and 20 in an array and then will fetch the mapped results from apps array based on Array#filter method along with Array#includes method.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

// Apps array
let apps = [
{id:10, address:&#39;Some street 1&#39;, city:&#39;City 1&#39;},
{id:20, address:&#39;Some street 2&#39;, city:&#39;City 2&#39;},
{id:20, address:&#39;Some street 2&#39;, city:&#39;City 2&#39;},
{id:30, address:&#39;Some street 3&#39;, city:&#39;City 3&#39;}
];
// Selected items array.
const selctedItems = [10, 20];
const result = apps.filter(({ id }) =&gt; selctedItems.includes(id));
// result
console.log(result);

<!-- end snippet -->

Update : Full working demo as per the author request (Descriptive comments have been added in the below code snippet itself).

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

// Input Array 1
let items = [
{id:1, name:&#39;Item 1&#39;, appId:10},
{id:2, name:&#39;Item 2&#39;, appId:20},
{id:3, name:&#39;Item 3&#39;, appId:20},
{id:4, name:&#39;Item 4&#39;, appId:30}
];
// Input Array 2
const apps = [
{id:10, address:&#39;Some street 1&#39;, city:&#39;City 1&#39;},
{id:20, address:&#39;Some street 2&#39;, city:&#39;City 2&#39;},
{id:30, address:&#39;Some street 3&#39;, city:&#39;City 3&#39;}
];
// Element on which checkboxes will get bind. 
var myDiv = document.getElementById(&quot;checkBoxes&quot;);
// Loop through each object of &quot;items&quot; array to create checkbox dynamically and bind in the &quot;myDiv&quot; variable which referes to &quot;checkBoxes&quot; element.
for (var i = 0; i &lt; items.length; i++) {
var checkBox = document.createElement(&quot;input&quot;);
var label = document.createElement(&quot;label&quot;);
checkBox.type = &quot;checkbox&quot;;
checkBox.value = items[i].appId;
myDiv.appendChild(checkBox);
myDiv.appendChild(label);
label.appendChild(document.createTextNode(items[i].name));
}
// Getting all the checkboxes elements for iteration.
var cbs = document.querySelectorAll(&#39;input[type=&quot;checkbox&quot;]&#39;);
// This variable will hold the selected checkboxes values.
let selectedItems = [];
// Iterate over each checkbox element and triggering an &quot;onchange&quot; event.
cbs.forEach(function(item) {
item.onchange = getCheckBoxValue;
});
// Method which is responsible to get all the selected checkbox values into an array.
function getCheckBoxValue() {
selectedItems = [];
cbs.forEach(function(item) {
if (item.checked) {
if (!selectedItems.includes(item.value)) {
selectedItems.push(item.value)
}
}
});
getFilteredValuesFromAnotherArr();
}
// Final method which is basically used to fetch the selected values from a second array based on the first array selections.
function getFilteredValuesFromAnotherArr() {
console.log(apps.filter(({ id }) =&gt; selectedItems.includes(id.toString())));
}

<!-- language: lang-html -->

&lt;div id=&quot;checkBoxes&quot;&gt;&lt;/div&gt;

<!-- end snippet -->

答案2

得分: 1

我建议将这两个数组合并起来。这将减少很多复杂性,使您的代码非常易于阅读。解决这个问题有很多方法,但以下是我会这样做的方法。

首先,我使用reduce函数为app数组创建一个字典。这使我能够拥有与items数组中的id相关联的索引,从而能够直接访问每个app项,而不必遍历整个数组。

一旦我有了字典,我可以轻松地通过映射items数组并为每个项创建一个新对象,其中包含原始项加上appDict中的app项来执行合并。

现在,您有一个包含解决问题所需的所有内容的单个数组,并且保持在O(n)的时间复杂度内。

const items = [
  {id:1, name:'Item 1', appId:10},
  {id:2, name:'Item 2', appId:20},
  {id:3, name:'Item 3', appId:20},
  {id:4, name:'Item 4', appId:30}
]
const apps = [
  {id:10, address:'Some street 1', city:'City 1'},
  {id:20, address:'Some street 2', city:'City 2'},
  {id:30, address:'Some street 3', city:'City 3'}
];
const appDict = apps.reduce((acc, {id, ...rest}) => ({...acc, [id]: rest}), {})
const combinedArr = items.map(item => ({...item, ...appDict[item.appId]})
英文:

My advice would be to merge the two arrays. This will remove a lot of complexity and make your code super easy to read. There are many ways to solve this problem, but the following is how I would do it.

Firstly I create a dictionary for the app array using the reduce function. This gives me the benefit of having indexes which correlate with the ids in the items array, allowing me to directly access each app item without looping the entire array.

Once I have the dictionary, I can easily perform the merge by mapping the items array and creating a new object for each item containing the original item + the app item from the appDict.

Now you have a single array with everything you need to solve the problem, and you remain within the O(n) time complexity.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const items = [
{id:1, name:&#39;Item 1&#39;, appId:10},
{id:2, name:&#39;Item 2&#39;, appId:20},
{id:3, name:&#39;Item 3&#39;, appId:20},
{id:4, name:&#39;Item 4&#39;, appId:30}
]
const apps = [
{id:10, address:&#39;Some street 1&#39;, city:&#39;City 1&#39;},
{id:20, address:&#39;Some street 2&#39;, city:&#39;City 2&#39;},
{id:30, address:&#39;Some street 3&#39;, city:&#39;City 3&#39;}
];
const appDict = apps.reduce((acc, {id, ...rest})=&gt; ({...acc, [id]: rest}), {})
const combinedArr = items.map(item=&gt;({...item, ...appDict[item.appId]}))

<!-- end snippet -->

答案3

得分: 0

[已更新]

这段代码完全符合你的需求:

let items = [
	{id: 1, name: '物品 1', appId: 10},
	{id: 2, name: '物品 2', appId: 20},
	{id: 3, name: '物品 3', appId: 20},
	{id: 4, name: '物品 4', appId: 30}
]

let apps = [
	{id: 10, address: '某条街 1', city: '城市 1'},
	{id: 20, address: '某条街 2', city: '城市 2'},
	{id: 20, address: '某条街 2', city: '城市 2'},
	{id: 30, address: '某条街 3', city: '城市 3'}
]

this.dataSource = items.filter(x => apps.findIndex(y => y.id === x.appId) >= 0);

解释

我们在items数组上运行filter,它会遍历该数组的每个元素,并检查你传入的函数是否对该元素返回true。它将通过此测试的元素添加到一个新数组中,并返回该数组。

我们传入的用于检查的函数为x => apps.findIndex(y => y.id === x.appId) >= 0,它使用数组中的另一个实用函数findIndex,其工作方式类似于filter。唯一的例外是它只返回一个项目以及它在数组中的位置。我们传入函数y => y.id === x.appId,它检查我们在apps数组中检查的项目是否是我们要查找的项目。如果找不到该项目,它会返回-1,因此我们只需检查是否大于等于0。

希望这对你有所帮助!

英文:

[UPDATED]

This code should suit your needs exactly:

let items = [
	{id: 1, name: &#39;Item 1&#39;, appId: 10},
	{id: 2, name: &#39;Item 2&#39;, appId: 20},
	{id: 3, name: &#39;Item 3&#39;, appId: 20},
	{id: 4, name: &#39;Item 4&#39;, appId: 30}
]

let apps = [
	{id: 10, address: &#39;Some street 1&#39;, city: &#39;City 1&#39;},
	{id: 20, address: &#39;Some street 2&#39;, city: &#39;City 2&#39;},
	{id: 20, address: &#39;Some street 2&#39;, city: &#39;City 2&#39;},
	{id: 30, address: &#39;Some street 3&#39;, city: &#39;City 3&#39;}
]

this.dataSource = items.filter(x =&gt; apps.findIndex(y =&gt; y.id === x.appId) &gt;= 0);

Explanation

We run filter on the items array, which goes through every element of that array, and checks if the function you pass in returns true or not for that element. It adds elements that pass this test to a new array, and returns that array.

The function we pass in for that check, x =&gt; apps.findIndex(y =&gt; y.id === x.appId) &gt;= 0 uses another utility function in Arrays, findIndex, which works a lot like filter. The exception is that it only returns one item, and the place it is in the array. We pass in the function y =&gt; y.id === x.appId, which sees if the item we're checking in the apps array is the one we're looking for. If it doesn't find the item, it returns -1, so we just check against it.

I hope this helps~!!

答案4

得分: 0

以下是已翻译的内容:

如果您想跟踪多个项目,请考虑这个简单的示例。假装应用程序 ID 10 和 30 已被选择。您需要将应用程序数组映射为包含原始信息以及所选项目结果的方式如下:

let items = [
  { id: 1, name: "Item 1", appId: 10 },
  { id: 2, name: "Item 2", appId: 20 },
  { id: 3, name: "Item 3", appId: 20 },
  { id: 4, name: "Item 4", appId: 30 },
];

let apps = [
  { id: 10, address: "Some street 1", city: "City 1" },
  { id: 20, address: "Some street 2", city: "City 2" },
  { id: 20, address: "Some street 2", city: "City 2" },
  { id: 30, address: "Some street 3", city: "City 3" },
];

const selectedAppIDs = [10, 30];

const result = apps
  .filter((app) => selectedAppIDs.includes(app.id))
  .map((app) => ({
    ...app,
    selectedItems: items.filter((x) => x.appId === app.id),
  }));

console.log(JSON.stringify(result));

结果:

[
  {"id":10,"address":"Some street 1","city":"City 1","selectedItems":[{"id":1,"name":"Item 1","appId":10}]},
  {"id":30,"address":"Some street 3","city":"City 3","selectedItems":[{"id":4,"name":"Item 4","appId":30}]}
]

查看此示例

英文:

If you want to keep track of multiple items, consider this simple example. Pretend App ID 10 and 30 are selected. You need to map the app array to contain the original information as well as the selected-item results like this:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

let items = [
{ id: 1, name: &quot;Item 1&quot;, appId: 10 },
{ id: 2, name: &quot;Item 2&quot;, appId: 20 },
{ id: 3, name: &quot;Item 3&quot;, appId: 20 },
{ id: 4, name: &quot;Item 4&quot;, appId: 30 },
];
let apps = [
{ id: 10, address: &quot;Some street 1&quot;, city: &quot;City 1&quot; },
{ id: 20, address: &quot;Some street 2&quot;, city: &quot;City 2&quot; },
{ id: 20, address: &quot;Some street 2&quot;, city: &quot;City 2&quot; },
{ id: 30, address: &quot;Some street 3&quot;, city: &quot;City 3&quot; },
];
const selectedAppIDs = [10, 30];
const result = apps
.filter((app) =&gt; selectedAppIDs.includes(app.id))
.map((app) =&gt; ({
...app,
selectedItems: items.filter((x) =&gt; x.appId === app.id),
}));
console.log(JSON.stringify(result));

<!-- end snippet -->

Results:

[{&quot;id&quot;:10,&quot;address&quot;:&quot;Some street 1&quot;,&quot;city&quot;:&quot;City 1&quot;,&quot;selectedItems&quot;:[{&quot;id&quot;:1,&quot;name&quot;:&quot;Item 1&quot;,&quot;appId&quot;:10}]},{&quot;id&quot;:30,&quot;address&quot;:&quot;Some street 3&quot;,&quot;city&quot;:&quot;City 3&quot;,&quot;selectedItems&quot;:[{&quot;id&quot;:4,&quot;name&quot;:&quot;Item 4&quot;,&quot;appId&quot;:30}]}]

Check out this example

答案5

得分: 0

使用.filter(...includes...) .map(...) 的答案结合了嵌套的线性操作,导致二次时间复杂度。 使用.filter(...findIndex...) 的答案也有相同的问题。

这里是一个最小的可复制示例。这个解决方案使用 -

  • 高效的 Set 以进行快速的 O(1) 查找
  • useMemo 以避免浪费计算
  • flatMap 以在单次遍历中组合 filter->map
function App({ items, apps }) {
  const [selected, setSelected] = React.useState(_ => new Set())
  const selectedApps = React.useMemo(
    () => new Set(Array from(selected, s => s.appId)),
    [selected]
  )
  const select = item => event => {
    const s = new Set(selected)
    if (s.has(item)) s.delete(item)
    else s add(item)
    setSelected(s)
  }
  return <div>
    {items.map((item, key) =>
      <div>
        <input
          key={key}
          type="checkbox"
          checked={selected.has(item)}
          onClick={select(item)}
        />
        {item.name}
      </div>
    )}
    {apps.flatMap((app, key) =>
      selectedApps.has(app.id)
        ? [<pre key={key}>{JSON.stringify(app)}</pre>]
        : []
    )}
  </div>
}

const items = [{id:1, name:'Item 1', appId:10},{id:2, name:'Item 2', appId:20},{id:3, name:'Item 3', appId:20},{id:4, name:'Item 4', appId:30}]
const apps = [{id:10, address:'Some street 1', city:'City 1'},{id:20, address:'Some street 2', city:'City 2'},{id:20, address:'Some street 2', city:'City 2'},{id:30, address:'Some street 3', city:'City 3'}]

ReactDOM.render(<App items={items} apps={apps} />, document.body)

请注意,上面的代码已经翻译成中文。

英文:

The answer using .filter(...includes...).map(...) combines nested linear operations which results in quadratic time complexity. The answer using .filter(...findIndex...) has the same problem.

Here's a minimal reproducible example. This solution uses -

  • efficient Set for fast O(1) lookups
  • useMemo to avoid wasted computation
  • flatMap to combine filter-&gt;map in a single pass

<!-- begin snippet: js hide: false console: true babel: true -->

<!-- language: lang-js -->

function App({ items, apps }) {
const [selected, setSelected] = React.useState(_ =&gt; new Set())
const selectedApps = React.useMemo(
() =&gt; new Set(Array.from(selected, s =&gt; s.appId)),
[selected]
)
const select = item =&gt; event =&gt; {
const s = new Set(selected)
if (s.has(item)) s.delete(item)
else s.add(item)
setSelected(s)
}
return &lt;div&gt;
{items.map((item, key) =&gt;
&lt;div&gt;
&lt;input
key={key}
type=&quot;checkbox&quot;
checked={selected.has(item)}
onClick={select(item)}
/&gt;
{item.name}
&lt;/div&gt;
)}
{apps.flatMap((app, key) =&gt;
selectedApps.has(app.id)
? [&lt;pre key={key}&gt;{JSON.stringify(app)}&lt;/pre&gt;]
: []
)}
&lt;/div&gt;
}
const items = [{id:1, name:&#39;Item 1&#39;, appId:10},{id:2, name:&#39;Item 2&#39;, appId:20},{id:3, name:&#39;Item 3&#39;, appId:20},{id:4, name:&#39;Item 4&#39;, appId:30}]
const apps = [{id:10, address:&#39;Some street 1&#39;, city:&#39;City 1&#39;},{id:20, address:&#39;Some street 2&#39;, city:&#39;City 2&#39;},{id:20, address:&#39;Some street 2&#39;, city:&#39;City 2&#39;},{id:30, address:&#39;Some street 3&#39;, city:&#39;City 3&#39;}]
ReactDOM.render(&lt;App items={items} apps={apps} /&gt;, document.body)

<!-- language: lang-html -->

&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js&quot;&gt;&lt;/script&gt;

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年2月8日 22:33:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/75387294.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定