隱形的亼

文章 评论 浏览 31

隱形的亼 2025-02-17 08:13:54

user_input.isdigit()只需告诉您输入是否仅包含数字。它返回布尔值,而不是数字的值。因此,您无法比较它以确定数字是否大于 0

实际发生的事情是布尔值 true false 转换为数字: true == 1 and false == 0 。这是将其与0进行比较。

做到这一点的最佳方法是调用 int()尝试将输入转换为整数,并使用 try/try/dek 来检测错误如果无法转换。如果成功转换,请检查那里是否是正面的。

def calc_minutes(user_input):
    try:
        user_input_int = int(user_input)
        if user_input_int <= 0:
            return 'ERROR: type a positive number'
        minutes_a_day = 1440
        calc_anwser = minutes_a_day * user_input_int
        return f'there are {calc_anwser} minutes in {user_input} days'
    except ValueError:
        return 'ERROR: type an integer'

user_input.isdigit() just tells you if the input only contains digits. It returns a boolean, not the value of the number. So you can't compare it to tell if the number is more than 0.

What's actually happening is that the boolean value True or False is converted to a number: True == 1 and False == 0. That's being compared with 0.

The best way to do this is to call int() to try to convert the input to an integer, and use try/except to detect the error if it can't be converted. If it converts successfully, check there to see if it's positive.

def calc_minutes(user_input):
    try:
        user_input_int = int(user_input)
        if user_input_int <= 0:
            return 'ERROR: type a positive number'
        minutes_a_day = 1440
        calc_anwser = minutes_a_day * user_input_int
        return f'there are {calc_anwser} minutes in {user_input} days'
    except ValueError:
        return 'ERROR: type an integer'

区分非智能者,负数,零不正确的代码

隱形的亼 2025-02-17 03:16:22

根据屏幕截图2(Python代码),Torch是库,该库未正确安装,并且由于问题中的要求尚不清楚,因此提供了要遵循的步骤流以使用工作过程将NLP连接到Azure Chat Bot 。

以下是 url 代码块。

As per the screenshot 2 (python code), torch is the library which was not installed properly and as the requirements are not clear in the question, providing the flow of steps to be followed to attach NLP to the azure chat bot with the working procedure.

The below is the URL for the code block.

在MS机器人中添加NLP模型在Azure上创建问题?

隱形的亼 2025-02-17 01:31:23

您可以尝试这样的事情:

WITH cte1 as (
SELECT distinct *
FROM 
table1
),
cte2 as 
(
  Select Name, Role, ROW_NUMBER() over (partition by name order by name) as rnk 
  from cte1 u 
  group by u.name, u.role
 )
      
SELECT * FROM cte2
where name in
(select name
from cte2
WHERE rnk > 1
group by name
)

我使用了一个不同的功能来删除任何重复项,然后使用Row_number()像您一样找到具有多行的名称。

You can try something like this:

WITH cte1 as (
SELECT distinct *
FROM 
table1
),
cte2 as 
(
  Select Name, Role, ROW_NUMBER() over (partition by name order by name) as rnk 
  from cte1 u 
  group by u.name, u.role
 )
      
SELECT * FROM cte2
where name in
(select name
from cte2
WHERE rnk > 1
group by name
)

I used a distinct function to remove any duplicates, then use the ROW_NUMBER() like you to find Names with multiple rows.

db fiddle link

仅在另一列不同时才在SQL中显示重复项?

隱形的亼 2025-02-16 18:49:04
import { useQuery, useMutation } from '@vue/apollo-composable'

jest.mock('@vue/apollo-composable', () => ({
  __esModule: true,
  useQuery: jest.fn(),
  useMutation: jest.fn()
}))
useQuery.mockImplementation(() => ({
  result: { value: testRes }
}))
useMutation.mockImplementation(() => ({
  onDone: jest.fn()
}))
import { useQuery, useMutation } from '@vue/apollo-composable'

jest.mock('@vue/apollo-composable', () => ({
  __esModule: true,
  useQuery: jest.fn(),
  useMutation: jest.fn()
}))
useQuery.mockImplementation(() => ({
  result: { value: testRes }
}))
useMutation.mockImplementation(() => ({
  onDone: jest.fn()
}))

VUE测试utils / Apollo-Composable检查是否称为USEMUNT

隱形的亼 2025-02-16 16:22:19

有一个内置的Terraform 函数。

> keys({a=1, c=2, d=3})
[
  "a",
  "c",
  "d",
]

因此,在您的情况下:

locals {
  account_map = {
    111111111111 = "DEV"
    222222222222 = "DEV"
    333333333333 = "STG"
    333333333333 = "PROD"
  }
  dev_accounts = keys(local.account_map)
}

output "dev_accounts" {
  value = local.dev_accounts
}

结果:

% terraform plan

Changes to Outputs:
  + dev_accounts = [
    + "111111111111",
    + "222222222222",
    + "333333333333",
  ]
...

terraform文档: https:https:// devevelovelveloper.hashicorp。 com/terraform/language/functions/键

There is a built-in Terraform keys function.

> keys({a=1, c=2, d=3})
[
  "a",
  "c",
  "d",
]

So, in your case:

locals {
  account_map = {
    111111111111 = "DEV"
    222222222222 = "DEV"
    333333333333 = "STG"
    333333333333 = "PROD"
  }
  dev_accounts = keys(local.account_map)
}

output "dev_accounts" {
  value = local.dev_accounts
}

Results to:

% terraform plan

Changes to Outputs:
  + dev_accounts = [
    + "111111111111",
    + "222222222222",
    + "333333333333",
  ]
...

Terraform docs: https://developer.hashicorp.com/terraform/language/functions/keys

将Terraform地图键转换为列表

隱形的亼 2025-02-15 20:18:09

根据Discord API, guild.channels.cache guildbasedChannel的数组对象。这样,您可以轻松地做:

interaction.guild.channels.cache.forEach((channel) => {
      channel.delete();
})

According to Discord API, guild.channels.cache is an array of GuildBasedChannel objects. With that, you can easily do:

interaction.guild.channels.cache.forEach((channel) => {
      channel.delete();
})

从Discord服务器获取所有频道,并使用Discord.js删除它们

隱形的亼 2025-02-15 12:50:45

根据评论,解决方案是 c:\ Windows \ synative \ firewall.cpl project&gt;属性&gt;构建选项卡“优先32位” 未添加。

您还可以参考此链接下的两个答案。

如何将我的Windows表单与.NET框架与蒸汽链接到没有构建错误的情况下

According to the comments,the solution is c:\windows\sysnative\firewall.cpl or Project > Properties > Build tab, "Prefer 32-bit" unticked.

https://learn.microsoft.com/en-us/windows/win32/winprog64/file-system-redirector

You can also refer to the two answers under this link.

how do i link my windows form with .NET framework to steam without build errors

system.componentmodel.win32 exception:找不到路径

隱形的亼 2025-02-14 15:28:12

您必须使用标题的归类值,然后您将获得工具提示文本。您不必滚动到元素。

期待(元素(by.id(“ xyz”))。getAttribute(“ title”))。tobe(“工具提示文本”);

You have to use atribute value of title then you will get the tooltip text. you dont have to scroll to the element.

expect(element(By.id("xyz")).getAttribute("title")).ToBe("Tool tip text");

如何在硒中的鼠标悬停在鼠标上检查工具提示消息?

隱形的亼 2025-02-14 06:16:26

错误“ [ERR_REQUIRE_ESM]:不支持不支持的require(require(),因为您要导入的软件包已转换为仅ESM的软件包,这意味着不能再将包装与require()导入。
使用npm i

The error "[ERR_REQUIRE_ESM]: require() not supported" occurs because a package you are importing has been converted to be an ESM only package, which means that the package cannot be imported with require() anymore.
Use npm i [email protected]

nanoid4在编码错误错误[err_require_esm]中:ES模块的require()

隱形的亼 2025-02-14 01:47:13

这是 searchPanel 。默认情况下,在列表视图上启用了它。

要将其实现到任何树视图,您只需在搜索视图中定义 searchpanel

对于帐户图表,他们使用以下内容:

<searchpanel class="account_root">
    <field name="root_id" icon="fa-filter" limit="0"/>
</searchpanel>

This is the searchpanel . By default, it is enabled on the the list view.

To implement it to any tree view, you have just to define the searchpanel in the search view.

For chart of accounts, they used the following:

<searchpanel class="account_root">
    <field name="root_id" icon="fa-filter" limit="0"/>
</searchpanel>

如何在Odoo的树视图中实现导航面板?

隱形的亼 2025-02-12 19:54:04

建议

如果您在Google Drive文件夹中有数百个Google电子表格文件,我同意@player0 最好使用脚本。使用 apps脚本您可以:您可以:

  1. 通过电子表格文件自动化该过程在您的驱动文件夹中。
  2. 仅过滤Google电子表格类型(例如,您有一堆
    内部不同的文件类型)。
  3. 获取范围数据&amp;按照您想要的方式处理它们。

请参阅下面的此示例,这些示例是从现有资源中得出的:

脚本:

function readSheetsInAFolder() {
  //FOLDER_ID is your drive folder ID
  var query = '"FOLDER_ID" in parents and trashed = false and ' +
    'mimeType = "application/vnd.google-apps.spreadsheet"';
  var range = "C3"; //The range to look for on every Spreadsheet files in the Drive folder
  var files, pageToken;
  var finalRes = [];

  do {
    files = Drive.Files.list({
      q: query,
      maxResults: 100,
      pageToken: pageToken
    });
    files.items.forEach(sheet => {
      finalRes.push(viewRangeValue(range, sheet.id));
    })
    pageToken = files.nextPageToken;
  } while (pageToken);
  const arrSum = array =>
    array.reduce(
        (sum, num) => sum + (Array.isArray(num) ? arrSum(num) : num * 1),
        0
    );

    var max = Math.max.apply(null, finalRes.map(function(row){ return Math.max.apply(Math, row) })); //Gets the largest number
    var min = Math.min.apply(null, finalRes.map(function(row){ return Math.min.apply(Math, row); })); //Gets the smallest number
    var sum = arrSum(finalRes) // Gets the sum
    console.log('RANGE VALUES: %s \nRANGE: %s \nTOTAL SHEET(s) FOUND: %s \n________________\nSUM OF VALUES: %s \nLargest Value: %s \nSmallest Value: %s',finalRes,range, files.items.length,sum,max,min)
}

function viewRangeValue(range, sheetID) {
  var sid = sheetID;
  var rn = range;
  var parms = { valueRenderOption: 'UNFORMATTED_VALUE', dateTimeRenderOption: 'SERIAL_NUMBER' };
  var res = Sheets.Spreadsheets.Values.get(sid, rn, parms);
  return res.values.map(num => {return parseInt(num)});
}

演示:

  • 样本测试驱动器文件夹(W/ 3测试电子表格文件):

每个 c3 在这3个文件中的每个文件上包含 0 10 6 6 value。 /p>

  • 在应用程序脚本编辑器上,我添加了驱动器&amp; sheet api在服务上:

”在此处输入映像说明“

结果

在运行脚本后

”

resources:

SUGGESTION

If you have hundreds of Google spreadsheet files in a Google Drive folder, I agree with @player0 that it is best to use a script. With the Apps Script, you can:

  1. Automate the process in iterating through Spreadsheet files in your Drive folder.
  2. Filter only the Google Spreadsheet type (e.g you have a bunch of
    different file types inside).
  3. Get the range data & process them the way you want.

See this sample below that was derived from existing resources:

Script:

function readSheetsInAFolder() {
  //FOLDER_ID is your drive folder ID
  var query = '"FOLDER_ID" in parents and trashed = false and ' +
    'mimeType = "application/vnd.google-apps.spreadsheet"';
  var range = "C3"; //The range to look for on every Spreadsheet files in the Drive folder
  var files, pageToken;
  var finalRes = [];

  do {
    files = Drive.Files.list({
      q: query,
      maxResults: 100,
      pageToken: pageToken
    });
    files.items.forEach(sheet => {
      finalRes.push(viewRangeValue(range, sheet.id));
    })
    pageToken = files.nextPageToken;
  } while (pageToken);
  const arrSum = array =>
    array.reduce(
        (sum, num) => sum + (Array.isArray(num) ? arrSum(num) : num * 1),
        0
    );

    var max = Math.max.apply(null, finalRes.map(function(row){ return Math.max.apply(Math, row) })); //Gets the largest number
    var min = Math.min.apply(null, finalRes.map(function(row){ return Math.min.apply(Math, row); })); //Gets the smallest number
    var sum = arrSum(finalRes) // Gets the sum
    console.log('RANGE VALUES: %s \nRANGE: %s \nTOTAL SHEET(s) FOUND: %s \n________________\nSUM OF VALUES: %s \nLargest Value: %s \nSmallest Value: %s',finalRes,range, files.items.length,sum,max,min)
}

function viewRangeValue(range, sheetID) {
  var sid = sheetID;
  var rn = range;
  var parms = { valueRenderOption: 'UNFORMATTED_VALUE', dateTimeRenderOption: 'SERIAL_NUMBER' };
  var res = Sheets.Spreadsheets.Values.get(sid, rn, parms);
  return res.values.map(num => {return parseInt(num)});
}

Demonstration:

  • Sample Test Drive Folder (w/ 3 test Spreadsheet files):

Every C3 cell on each of these 3 files contain either 0,10 or 6 value.

enter image description here

  • On the Apps Script Editor, I've added the Drive & Sheets API on the services:

enter image description here

Result

After running the script:

enter image description here

Resources:

我可以从文件夹中的每个Google表中选择一个单元格吗?

隱形的亼 2025-02-12 15:32:00

我找到了解决自己问题的解决方案。原因是原因是因为我从一个旧的React项目中复制了此 .htaccess ,在该项目支持React-Router。

在我的NextJS项目中,我只需要删除 .html .htaccess 文件中的扩展。请参阅下面的示例:

Options +FollowSymLinks
RewriteEngine On
RewriteCond %{ENV:HTTPS} !=on
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^([^\.]+)$ $1.html [NC,L]
</IfModule>

I found a solution for my own problem. The problem was causes because I copied this .htaccess from an old React project where it was supporting the react-router.

Within my NextJS project I only had to remove the .html extension inside the .htaccess file. See example below:

Options +FollowSymLinks
RewriteEngine On
RewriteCond %{ENV:HTTPS} !=on
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^([^\.]+)$ $1.html [NC,L]
</IfModule>

静态服务的NextJS网站正在添加页面刷新的尾声

隱形的亼 2025-02-12 13:26:30

看到了各种迹象表明这是不可能的。

您应该注意的至关重要的事情是,您只能为以这种方式声明的环境变量分配文字值。您无法在运行时分配动态值。如果您想更改&lt; ...&gt;的价值。以上可变,您必须更改buildspec文件,然后再次将更改推向存储库。因此,它就像硬编码的参数值。但这比键入“阶段”部分中所需的所有命令要好。

尝试了多种方法,包括

  • 名称解析为pre_build的第一步
  • 运行自定义powershell脚本以将分支
  • 除了尝试简单地设置pre_build中的局部var外,我还 方法

似乎有效的是使用伪影/名称本身中的替换命令:

artifacts:
  files:
    - .\Dummy\bin\Debug\*
  name: ${env:APPNAME}/${env:APPNAME}-$($CODEBUILD_WEBHOOK_HEAD_REF.replace('refs/heads/', '')).zip
  discard-paths: yes

创建此伪像:dummyapp \ dummyapp-develop.zip

Saw various indications that this is not possible.

https://blog.shikisoft.com/define-environment-vars-aws-codebuild-buildspec/

The crucial thing you should note here is that you can only assign literal values to the environment variables declared this way. You cannot assign dynamic values at runtime. If you would like to change the value of the <...> variable above, you have to change your buildspec file and push your changes to your repository again. So it is like hardcoding parameter values. But it is better than typing the in all commands needed in the phases section.

In addition to trying to simply set the local var in pre_build, I tried a number of approaches, including

  • running a custom powershell script to parse the Branch name as the first step in the pre_build
  • running the command in the variable declaration itself
  • calling the prsh SetEnvironmentVariable method

The thing that seems to work is using the replace command down in the artifact/name itself:

artifacts:
  files:
    - .\Dummy\bin\Debug\*
  name: ${env:APPNAME}/${env:APPNAME}-$($CODEBUILD_WEBHOOK_HEAD_REF.replace('refs/heads/', '')).zip
  discard-paths: yes

created this artifact: DummyApp\DummyApp-develop.zip

AWS CodeBuild buildspec-对阶段部分中的变量的更改是否可用?

隱形的亼 2025-02-12 12:08:49
SELECT T.ANI AS MOBILE
FROM ODCalls AS T
GROUP BY T.ANI
HAVING MIN(CAST(T.CallLocalTime AS DATE)=CAST(GETDATE()AS DATE)

您可以尝试这样的事情。我不确定有关DateTime可能出现问题的示例数据。该查询应检测到今天已经打了第一个电话的手机。

SELECT T.ANI AS MOBILE
FROM ODCalls AS T
GROUP BY T.ANI
HAVING MIN(CAST(T.CallLocalTime AS DATE)=CAST(GETDATE()AS DATE)

You can try something like this. I am not completely sure with out sample data about possible issues with datetime. This query should detect mobile phones, which have made the first call today.

检查今天的记录是否已经存在

隱形的亼 2025-02-12 05:40:04

对于这些更自定义的比较输出,我建议抛弃比较对象和进行自由泳,以便准确地控制您想要的东西。

一旦我们确定了如何匹配两个数据集之间的记录,我们可以通过当前对象的每个属性循环,并将它们与上一个文件中匹配对象的相同属性进行比较。如果值匹配,则我们应该输出一个空字符串。如果它们不匹配,我们应该输出当前对象的值。我们将始终输出我们选择匹配的属性的值,在这种情况下是“名称”属性。

# TEST DATA
$previousFile = @'
Name        UserPrincipalName   NickName    Age  Sex
UserUser 1  [email protected]      User1       20   M
UserUser 2  [email protected]       User2       20   M
UserUser 3  [email protected]       User3       20   M
UserUser 4  [email protected]       User90      20   M
UserUser 5  [email protected]       User91      20   M
'@

$currentFile = @'
Name        UserPrincipalName   NickName    Age  Sex
UserUser 1  [email protected]      User1       20   M
UserUser 2  [email protected]      User2       20   M
UserUser 3  [email protected]      User3       20   M
UserUser 4  [email protected]      User4       20   M
UserUser 5  [email protected]      User5       20   M
UserUser 6  [email protected]      User6       20   M
'@

$previous = $previousFile -replace ' {2,}', ',' | ConvertFrom-Csv
$current = $currentFile -replace ' {2,}', ',' | ConvertFrom-Csv
# END TEST DATA

# Set which property should be used to match records from current to previous
$matchPropertyName = 'Name'

$current | ForEach-Object {
    $obj = $_
    $match = $previous.where({ $_.$matchPropertyName -eq $obj.$matchPropertyName })
    if ($match) {
        $out = [ordered]@{}

        # loop through all the properties in current objects to determine whether to show them or not
        $obj.psobject.Properties | ForEach-Object {
            # if property = 'Name' then include the value as record Identifier
            if ($_.Name -eq $matchPropertyName) { $out[$_.Name] = $_.Value }

            # else if value of property in current matches previous set value to empty string
            elseif ($_.Value -eq $match[0].($_.Name)) {
                $out[$_.Name] = ''
            }

            # else current value does not match previous value so output current value
            else {
                $out[$_.Name] = $_.Value
            }
        }
        [pscustomobject]$out
    }

    # if not matched by 'Name' property then consider as new object and output all values
    else {
        $obj
    }
}

输出

Name       UserPrincipalName NickName Age Sex
----       ----------------- -------- --- ---
UserUser 1
UserUser 2 [email protected]
UserUser 3 [email protected]
UserUser 4 [email protected]    User4        
UserUser 5 [email protected]    User5
UserUser 6 [email protected]    User6    20  M

有关此解决方案要注意的一件事是,它不考虑已删除的行(即,以前存在但已在当前已删除的行),尽管这似乎是您在您自己的示例中所追求的仅过滤左侧。


更新

响应您的其他信息的 ,这是一个更新的解决方案,该解决方案不包括未改变的记录,并包含更多详细信息,希望可以帮助您更好地了解正在发生的事情。为了不输出不变的对象,在循环并比较对象时,我们可以跟踪对象是否已在变量中发生变化,然后只有在我们知道有更改时才输出对象。

# TEST DATA
$previousFile = @'
Name        UserPrincipalName   NickName    Age  Sex
UserUser 1  [email protected]      User1       20   M
UserUser 2  [email protected]      User2       20   M
UserUser 3  [email protected]      User3       20   M
UserUser 4  [email protected]      User4       20   M
UserUser 5  [email protected]      User5       20   M
UserUser 6  [email protected]      User6       20   M
'@

$currentFile = @'
Name        UserPrincipalName   NickName    Age  Sex
UserUser 1  [email protected]      User1       20   M
UserUser 2  [email protected]      User2       20   M
UserUser 3  [email protected]      User3       20   F
UserUser 4  [email protected]      User_4       20   M
UserUser 5  [email protected]      User_5       20   M
UserUser 6  [email protected]      User_6       30   M
'@

$previous = $previousFile -replace ' {2,}', ',' | ConvertFrom-Csv
$current = $currentFile -replace ' {2,}', ',' | ConvertFrom-Csv
# END TEST DATA

# Set which property should be used to match records from current to previous
$matchPropertyName = 'Name'

$current | ForEach-Object {
    # in ForEach-Object scriptblock $_ is the current object being processed.
    # Below we assign $_ to $obj in order to reference it in the
    # $previous.where({}) scriptblock where $_ will reference it's own object
    # from the $previous array
    $obj = $_

    # Here we are looking for an object in $previous array where property $matchPropertyName, which we have
    # defined earlier as being equal to 'Name', matches our current object's 'Name' property.  We stick this match
    # in a variable called $match
    $match = $previous.where({ $_.$matchPropertyName -eq $obj.$matchPropertyName })

    # if we find a matching record in $previous
    if ($match) {
        # We will use $isModified to keep track of whether a changes was found in any of the properties
        $isModified = $false

        # create an ordereddictionary in which to build our own object with
        # we use this to capture the property names and values using key-value pairs
        # $out[<keyname>] = <value>
        # later we can easily convert this to an object using the [pscustomobject] type accelerator
        $out = [ordered]@{}

        # Loop through all the properties in current object to determine whether to show them or not.
        # Here we use the an intrinsic member called .psobject to access a collection containing all
        # the object's properties and values and loop through each of them.
        # i.e., we loop through objects that look like this
        #
        # Name              Value
        # ----              -----
        # Name              UserUser 1
        # UserPrincipalName [email protected]
        # NickName          User1
        # Age               20
        # Sex               M   
        
        # there are 5 properties so we will be looping 5 times in the following ForEach-Object call, 
        # once for each property of the current object
        $obj.psobject.Properties | ForEach-Object {
            # if property = 'Name' then include the value as record Identifier
            if ($_.Name -eq $matchPropertyName) { $out[$_.Name] = $_.Value }

            # else if value of property in current matches previous set value to empty string
            elseif ($_.Value -eq $match[0].($_.Name)) {
                $out[$_.Name] = ''
            }

            # else current value does not match previous value so output current value
            else {
                # create a key-value pair in our dictionary containing the property name and value
                # e.g., $out['NickName'] = 'User1'
                $out[$_.Name] = $_.Value

                # update $isModified to true so we know to include in the output
                $isModified = $true
            }
        }

        # Check if the object has been modified and if so, output it.
        # We use the [pscustomobject] type accelerator here to convert our ordereddictionary to an object
        # containing our key-value pairs as properties.
        if ($isModified) { [pscustomobject]$out }
    }

    # if we don't find a matching object in $previous then consider as new object and output all values
    else {
        $obj
    }
}

参考:

For these more customized compare outputs I suggest ditching Compare-Object and going freestyle in order to control exactly what you want.

Once we determine how we want to match records between the two datasets we can loop through each property of the current objects and compare them to the same property of the matched object in the previous file. If the values match then we should output an empty string. If they do not match, they we should output the value of the current object. We will always output the value of the property we choose to match on which in this case is the 'Name' property.

# TEST DATA
$previousFile = @'
Name        UserPrincipalName   NickName    Age  Sex
UserUser 1  [email protected]      User1       20   M
UserUser 2  [email protected]       User2       20   M
UserUser 3  [email protected]       User3       20   M
UserUser 4  [email protected]       User90      20   M
UserUser 5  [email protected]       User91      20   M
'@

$currentFile = @'
Name        UserPrincipalName   NickName    Age  Sex
UserUser 1  [email protected]      User1       20   M
UserUser 2  [email protected]      User2       20   M
UserUser 3  [email protected]      User3       20   M
UserUser 4  [email protected]      User4       20   M
UserUser 5  [email protected]      User5       20   M
UserUser 6  [email protected]      User6       20   M
'@

$previous = $previousFile -replace ' {2,}', ',' | ConvertFrom-Csv
$current = $currentFile -replace ' {2,}', ',' | ConvertFrom-Csv
# END TEST DATA

# Set which property should be used to match records from current to previous
$matchPropertyName = 'Name'

$current | ForEach-Object {
    $obj = $_
    $match = $previous.where({ $_.$matchPropertyName -eq $obj.$matchPropertyName })
    if ($match) {
        $out = [ordered]@{}

        # loop through all the properties in current objects to determine whether to show them or not
        $obj.psobject.Properties | ForEach-Object {
            # if property = 'Name' then include the value as record Identifier
            if ($_.Name -eq $matchPropertyName) { $out[$_.Name] = $_.Value }

            # else if value of property in current matches previous set value to empty string
            elseif ($_.Value -eq $match[0].($_.Name)) {
                $out[$_.Name] = ''
            }

            # else current value does not match previous value so output current value
            else {
                $out[$_.Name] = $_.Value
            }
        }
        [pscustomobject]$out
    }

    # if not matched by 'Name' property then consider as new object and output all values
    else {
        $obj
    }
}

Output

Name       UserPrincipalName NickName Age Sex
----       ----------------- -------- --- ---
UserUser 1
UserUser 2 [email protected]
UserUser 3 [email protected]
UserUser 4 [email protected]    User4        
UserUser 5 [email protected]    User5
UserUser 6 [email protected]    User6    20  M

One thing to note about this solution is it does not account for lines that have been removed (i.e., lines that existed in previous but have been removed in current), though this appears to be what you were going for in your own example by filtering for only the leftside.


UPDATE

In response to your additional information, here is an updated solution which does not include unchanged records and includes more detail to hopefully help you understand better what is happening. To not output unchanged objects, when looping through and comparing the objects we can keep track of whether an object has changed in a variable and then only output the object if we know there were changes.

# TEST DATA
$previousFile = @'
Name        UserPrincipalName   NickName    Age  Sex
UserUser 1  [email protected]      User1       20   M
UserUser 2  [email protected]      User2       20   M
UserUser 3  [email protected]      User3       20   M
UserUser 4  [email protected]      User4       20   M
UserUser 5  [email protected]      User5       20   M
UserUser 6  [email protected]      User6       20   M
'@

$currentFile = @'
Name        UserPrincipalName   NickName    Age  Sex
UserUser 1  [email protected]      User1       20   M
UserUser 2  [email protected]      User2       20   M
UserUser 3  [email protected]      User3       20   F
UserUser 4  [email protected]      User_4       20   M
UserUser 5  [email protected]      User_5       20   M
UserUser 6  [email protected]      User_6       30   M
'@

$previous = $previousFile -replace ' {2,}', ',' | ConvertFrom-Csv
$current = $currentFile -replace ' {2,}', ',' | ConvertFrom-Csv
# END TEST DATA

# Set which property should be used to match records from current to previous
$matchPropertyName = 'Name'

$current | ForEach-Object {
    # in ForEach-Object scriptblock $_ is the current object being processed.
    # Below we assign $_ to $obj in order to reference it in the
    # $previous.where({}) scriptblock where $_ will reference it's own object
    # from the $previous array
    $obj = $_

    # Here we are looking for an object in $previous array where property $matchPropertyName, which we have
    # defined earlier as being equal to 'Name', matches our current object's 'Name' property.  We stick this match
    # in a variable called $match
    $match = $previous.where({ $_.$matchPropertyName -eq $obj.$matchPropertyName })

    # if we find a matching record in $previous
    if ($match) {
        # We will use $isModified to keep track of whether a changes was found in any of the properties
        $isModified = $false

        # create an ordereddictionary in which to build our own object with
        # we use this to capture the property names and values using key-value pairs
        # $out[<keyname>] = <value>
        # later we can easily convert this to an object using the [pscustomobject] type accelerator
        $out = [ordered]@{}

        # Loop through all the properties in current object to determine whether to show them or not.
        # Here we use the an intrinsic member called .psobject to access a collection containing all
        # the object's properties and values and loop through each of them.
        # i.e., we loop through objects that look like this
        #
        # Name              Value
        # ----              -----
        # Name              UserUser 1
        # UserPrincipalName [email protected]
        # NickName          User1
        # Age               20
        # Sex               M   
        
        # there are 5 properties so we will be looping 5 times in the following ForEach-Object call, 
        # once for each property of the current object
        $obj.psobject.Properties | ForEach-Object {
            # if property = 'Name' then include the value as record Identifier
            if ($_.Name -eq $matchPropertyName) { $out[$_.Name] = $_.Value }

            # else if value of property in current matches previous set value to empty string
            elseif ($_.Value -eq $match[0].($_.Name)) {
                $out[$_.Name] = ''
            }

            # else current value does not match previous value so output current value
            else {
                # create a key-value pair in our dictionary containing the property name and value
                # e.g., $out['NickName'] = 'User1'
                $out[$_.Name] = $_.Value

                # update $isModified to true so we know to include in the output
                $isModified = $true
            }
        }

        # Check if the object has been modified and if so, output it.
        # We use the [pscustomobject] type accelerator here to convert our ordereddictionary to an object
        # containing our key-value pairs as properties.
        if ($isModified) { [pscustomobject]$out }
    }

    # if we don't find a matching object in $previous then consider as new object and output all values
    else {
        $obj
    }
}

References:

比较2个Excel文件并仅输出差异(PowerShell)

更多

推荐作者

櫻之舞

文章 0 评论 0

弥枳

文章 0 评论 0

m2429

文章 0 评论 0

野却迷人

文章 0 评论 0

我怀念的。

文章 0 评论 0

更多

友情链接

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文