心在旅行

文章 评论 浏览 29

心在旅行 2025-02-20 21:13:30

看得更深入,不幸的是,这比看起来更复杂 - 确实存在一个基本问题。

PG支持传输参数数据的两种方法:文本和二进制。 regconfig 的二进制编码是一个简单的int(iirc a oid键在pg_catalog.pg_ts_config表中)。因此,在二进制文件中发送参数化的regconfig意味着您需要在pg_ts_config中按名称查找regconfig,获取OID(德语为13395),然后发送该代替文本表示(“德语”)。

现在,PG确实具有从文本到RegConfig的隐式转换:如果您在需要regconfig的上下文中指定了字面的“德语”,那么PG将为您提供幕后的查找。但是,当明确指定类型时,不会发生这种隐式转换:

SELECT plainto_tsquery('german', 'some test text'); -- works
SELECT plainto_tsquery('german'::text, 'some test text'); --fails

现代NPGSQL始终将二进制编码用于其参数,并且始终明确指定它们上的类型,这就是为什么不会发生隐式转换并且查询失败的原因。

NPGSQL的旧版本有时在查询字符串中插值参数(同时提供逃脱以再次保护SQL注入),这就是为什么它可以在旧版本中使用的原因。

除了所有的技术之外,我都同意这是一个不幸的情况...除非您要下载和cache pg_ts_config,否则您对RegConfig的明确铸件的解决方案可能是最好的,在这种情况下,您可以发送OID(但是那是似乎一无所有)。

Looked deeper into it and this is unfortunately more complicated than it seems - there's indeed a fundamental issue here.

PG supports two ways of transferring parameter data: text and binary. The binary encoding of regconfig is a simple int (IIRC an oid key in the pg_catalog.pg_ts_config table). So sending a parameterized regconfig in binary would mean that you need to look up your regconfig by name in pg_ts_config, get the oid (13395 for german), and then send that instead of the textual representation ("german").

Now, PG does have an implicit conversion from text to regconfig: if you specify a literal "german" in a context where regconfig is required, PG will do that lookup for you behind the scenes. However, this implicit conversion doesn't happen when the type is explicitly specified:

SELECT plainto_tsquery('german', 'some test text'); -- works
SELECT plainto_tsquery('german'::text, 'some test text'); --fails

Modern Npgsql always uses binary encoding for its parameters, and always explicitly specifies types on them, which is why no implicit conversion happens and the query fails.

Old versions of Npgsql sometimes interpolated parameters into the query string (while providing escaping to protect again SQL injection), which is why it may have worked in old versions.

Beyond all the technicalities, I agree that this is an unfortunate situation... Your solution with the explicit cast to regconfig is probably the best one, unless you want to download and cache pg_ts_config, in which case you can send the oid (but that seems like a lot of trouble for nothing).

如何用NPGSQL 6作为存储过程执行PostgreSQL函数?

心在旅行 2025-02-20 03:26:10

首先,我喜欢您对边缘路由的解决方案,并希望为此看到代码。

其次,以下是我使用NetGraph的尝试,这是我编写(并维护)的网络可视化库。
NetGraph很容易安装( pip internetgraph ),并且接受 graph 来自各种网络分析库(NetworkX,igraph,Graph-tool)的对象,因此不应该有任何摩擦。

shell 节点布局使用所谓的中位启发式层中的节点以减少边缘交叉点。
弯曲边缘布局使用Fruchterman-Reingold算法的变体来分发边缘控制点,以便在可能的情况下避免边缘避免节点(彼此)。

#!/usr/bin/env python
import numpy as np
import matplotlib.pyplot as plt
import networkx as nx

from netgraph import Graph # pip install netgraph


# from the question:
G = nx.read_graphml("tmp/test.graphml")
indices = set([idx for n, idx in G.nodes.data('index')])
shells = [[n for n, idx in G.nodes.data('index') if idx == x] for x in indices]
radii = [np.log(idx)/np.log(max(indices)) for n, idx in G.nodes.data('index')]
node_labels = {n: idx for n, idx in G.nodes.data('index')}

# define a bounding box for the node layout
max_radius = np.max(radii)
origin = (-max_radius, -max_radius)
scale = (2 * max_radius, 2 * max_radius)

# initialise a figure
fig, ax = plt.subplots(figsize=(10, 8))

# indicate shells
radii = np.unique(radii)
for radius in radii[::-1]:
    ax.add_patch(plt.Circle((0, 0), radius=radius, facecolor='white', edgecolor='lightgray'))

# plot graph on top
g = Graph(G,
          node_size=6,
          edge_width=2,
          node_labels=node_labels,
          node_layout='shell',
          node_layout_kwargs=dict(shells=shells, radii=radii),
          edge_layout='curved',
          edge_layout_kwargs=dict(k=0.05), # larger values -> straighter edges
          origin=origin,
          scale=scale,
          arrows=True,
          ax=ax
)
plt.show()

First of all, I love your solution to the edge routing, and would love to see the code for that.

Secondly, below is my attempt using netgraph, which is a network visualisation library I wrote (and maintain).
Netgraph is easily installable (pip install netgraph), and accepts Graph objects from various network analysis libraries (networkx, igraph, graph-tool), so there shouldn't be any friction.

enter image description here

The shell node layout uses the so-called median heuristic to order the nodes within a layer to reduce edge crossings.
The curved edge layout uses a variant of the Fruchterman-Reingold algorithm to distribute the edge control points such that edges avoid nodes (and each other) -- where possible.

#!/usr/bin/env python
import numpy as np
import matplotlib.pyplot as plt
import networkx as nx

from netgraph import Graph # pip install netgraph


# from the question:
G = nx.read_graphml("tmp/test.graphml")
indices = set([idx for n, idx in G.nodes.data('index')])
shells = [[n for n, idx in G.nodes.data('index') if idx == x] for x in indices]
radii = [np.log(idx)/np.log(max(indices)) for n, idx in G.nodes.data('index')]
node_labels = {n: idx for n, idx in G.nodes.data('index')}

# define a bounding box for the node layout
max_radius = np.max(radii)
origin = (-max_radius, -max_radius)
scale = (2 * max_radius, 2 * max_radius)

# initialise a figure
fig, ax = plt.subplots(figsize=(10, 8))

# indicate shells
radii = np.unique(radii)
for radius in radii[::-1]:
    ax.add_patch(plt.Circle((0, 0), radius=radius, facecolor='white', edgecolor='lightgray'))

# plot graph on top
g = Graph(G,
          node_size=6,
          edge_width=2,
          node_labels=node_labels,
          node_layout='shell',
          node_layout_kwargs=dict(shells=shells, radii=radii),
          edge_layout='curved',
          edge_layout_kwargs=dict(k=0.05), # larger values -> straighter edges
          origin=origin,
          scale=scale,
          arrows=True,
          ax=ax
)
plt.show()

图形图:带有给定节点半径和非旋转边缘的径向布局

心在旅行 2025-02-20 03:24:28

@CID和@xing评论都是正确的。
您需要更改 isalnum()条件,然后使用 i 应该是 j

下次只需添加一些调试打印并查看流程,您将很快确定自己出了问题的位置。

这是固定版本。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define MAXR 100
#define MAXC 10     
#define TERMINATOR "END"

int main()
{
    char phrase[MAXR];
    char text[MAXC][MAXR];
  
    int i;
    int countalnum = 0;
    int countchar = 0;

    for (i = 0; i < MAXC; i++) {
  
        if (!fgets(phrase, MAXR, stdin))
            break;

        int len = strlen(phrase); // better to cache this value
        // strip the trailing newline if any
        if (len > 0 && phrase[len - 1] == '\n')
            phrase[--len] = '\0';

        if (strcmp(phrase, TERMINATOR) == 0) {
            break;
        }   
    
        for (int j = 0; j < len; j++) {
            countchar++;
            if (isalnum((unsigned char)phrase[j]))
                countalnum++;
        }
    
        strcpy(text[i], phrase);
    }

    // The result doesn't include the terminator "END"
    printf("Total chars: %d\n", countchar);
    printf("Total alphanumeric chars: %d\n", countalnum);
    return 0;
}

Both @Cid and @xing comments are correct.
you need to change the isalnum() condition and you used i where it should have been j.

Next time just add some debug prints and see the flow, you will very quickly figure where you have gone wrong.

Here is a fixed version.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define MAXR 100
#define MAXC 10     
#define TERMINATOR "END"

int main()
{
    char phrase[MAXR];
    char text[MAXC][MAXR];
  
    int i;
    int countalnum = 0;
    int countchar = 0;

    for (i = 0; i < MAXC; i++) {
  
        if (!fgets(phrase, MAXR, stdin))
            break;

        int len = strlen(phrase); // better to cache this value
        // strip the trailing newline if any
        if (len > 0 && phrase[len - 1] == '\n')
            phrase[--len] = '\0';

        if (strcmp(phrase, TERMINATOR) == 0) {
            break;
        }   
    
        for (int j = 0; j < len; j++) {
            countchar++;
            if (isalnum((unsigned char)phrase[j]))
                countalnum++;
        }
    
        strcpy(text[i], phrase);
    }

    // The result doesn't include the terminator "END"
    printf("Total chars: %d\n", countchar);
    printf("Total alphanumeric chars: %d\n", countalnum);
    return 0;
}

我在c中对isalnum()做错了什么?

心在旅行 2025-02-20 03:21:45

他们泄漏的是

,我不知道您在谈论哪个示例。
如果您澄清这一点(例如,通过添加链接),我可能可以编辑并提供更好的答案。

攻击RSA时,通常假定已知 n e (公共模量和指数)。
要打破RSA,我们需要恢复私有指数 d
但是,有多种方法可以重建 d
由于 n = p * q ,泄漏 p q 将琐碎地恢复 p = n/q (或 Q = N / P < / code>分别)。
知道 p q ,我们可以计算 d = e^( - 1)mod phi(n)(其中 phi(n) )=(p-1) *(q-1))。
当然,泄漏 d 本身也足够了。
要打破CRT-RSA,可以使用 dq dp 来计算Primes p q q
,从而恢复 d

位错误率

要获得位错误率,您必须知道正确的结果,然后按以下方式进行计算:

number of incorrectly leaked bits / total bits of the secret

例如,如果我泄漏了位 10001 ,但是正确的键是 10101 ,位错误率为:

1 / 5 = 20% 

由于泄漏的位之一是不正确的。

What they leak

I don't know which example specifically you are talking about.
If you clarify this (e.g., by adding a link) I may be able to edit this and provide a better answer.

When attacking RSA, it is usually assumed that N and e (the public modulus and exponent) are known.
To break RSA, we need to recover the private exponent d.
However, there are multiple ways to reconstruct d:
Since N = p * q, leaking either p or q will trivially recover p = N / q (or q = N / p respectively).
Knowing p and q, we can calculate d = e^(-1) mod phi(N) (where phi(N) = (p-1) * (q-1)).
Of course, leaking d itself will also suffice.
To break CRT-RSA, leaking either dq or dp can be used to calculate one of the primes p or q, thus recovering d.

Bit Error Rate

To get the bit error rate, you have to know the correct result, then you calculate it the following way:

number of incorrectly leaked bits / total bits of the secret

For example, if I leak the bits 10001, but the correct key is 10101, the bit error rate is:

1 / 5 = 20% 

Since one of the leaked bits is incorrect.

如何计算RSA上冲洗的位错误率

心在旅行 2025-02-19 17:37:52

我只想提及我在这个问题的一部分中看到的两个替代选项。

  1. 只需在午夜到每个月的第一个即将运行该功能。根据您的用例,这可能足够好。

  2. 每个月将功能重新安排到下个月的最后一天的特定日期。

I just want to mention two alternative options I see for the end of month part of the question.

  1. Simply run the function just past midnight to the 1st of each month. Depending on your use case this may be good enough.

  2. Reschedule the function each month to the specific date which will be the last day of the next month.

Google Cloud Scheduler触发的最后一天

心在旅行 2025-02-19 13:59:53
wait = WebDriverWait(d, 20)
d.get('https://developers.humana.com/Resource/PCTFilesList?fileType=innetwork')
for i in range(2,101):
    time.sleep(1)
    j=i
    if i>5:
        j=5
    #links=d.find_elements(By.CSS_SELECTOR,"a.download-pct-file-link")
    #print(len(links))
    #for link in links:
        # link.click()
    wait.until(EC.element_to_be_clickable((By.XPATH, f"//a[@data-dt-idx='{j}']"))).click()
    print(f"//a[@data-dt-idx='{j}']")

我知道它可以通过页面,而将值切换到第5页之后单击为5,data-dx-idx从2-5开始,然后停留在5。处理谷子。

进口:

import time
wait = WebDriverWait(d, 20)
d.get('https://developers.humana.com/Resource/PCTFilesList?fileType=innetwork')
for i in range(2,101):
    time.sleep(1)
    j=i
    if i>5:
        j=5
    #links=d.find_elements(By.CSS_SELECTOR,"a.download-pct-file-link")
    #print(len(links))
    #for link in links:
        # link.click()
    wait.until(EC.element_to_be_clickable((By.XPATH, f"//a[@data-dt-idx='{j}']"))).click()
    print(f"//a[@data-dt-idx='{j}']")

I got it to go through the pages while switching the value to click to be 5 after page 5.data-dx-idx went from 2-5 then stayed at 5.You can most likely do it without time.sleep() if you handle the stales.

Import:

import time

我们如何从URL下载多个CSV文件?

心在旅行 2025-02-19 04:25:06

首先,您需要为服务数量创建一个维度表。

您可以使用电源查询来执行此操作:

let
    Source = Table.FromList({1..List.Count(List.Distinct(Supported[Service Type]))},Splitter.SplitByNothing(),{"Number of Services"}),
    #"Changed Type" = Table.TransformColumnTypes(Source,{{"Number of Services", Int64.Type}})
in
    #"Changed Type"

或使用DAX:

Services = GENERATESERIES ( 1, DISTINCTCOUNT ( Supported[Service Type] ) )

然后根据需要重命名列。

现在您可以创建一些措施:

使用的服务数量:

Number of Services Used = DISTINCTCOUNT ( Supported[Service Type] )

人:

People = 
    COUNTROWS ( 
        FILTER ( 
            SUMMARIZE ( 
                Supported,
                Supported[SERIALNUMBER],
                "NumServices", [Number of Services Used]
            ),
            [NumServices] >= MIN ( Services[Number of Services] ) && 
            [NumServices] <= MAX ( Services[Number of Services] )
        )
    )

人(累积):

People (Cumulative) = 
    COUNTROWS ( 
        FILTER ( 
            SUMMARIZE ( 
                Supported,
                Supported[SERIALNUMBER],
                "NumServices", [Number of Services Used]
            ),
            [NumServices] >= MIN ( Services[Number of Services] )
        )
    )

这给出了以下内容,对于您的(微小)数据示例:

First of all, you need to create a dimension table for the Number of Services.

You can do this using Power Query:

let
    Source = Table.FromList({1..List.Count(List.Distinct(Supported[Service Type]))},Splitter.SplitByNothing(),{"Number of Services"}),
    #"Changed Type" = Table.TransformColumnTypes(Source,{{"Number of Services", Int64.Type}})
in
    #"Changed Type"

Or using DAX:

Services = GENERATESERIES ( 1, DISTINCTCOUNT ( Supported[Service Type] ) )

then rename column as required.

Now you can create a couple of measures:

Number of Services Used:

Number of Services Used = DISTINCTCOUNT ( Supported[Service Type] )

People:

People = 
    COUNTROWS ( 
        FILTER ( 
            SUMMARIZE ( 
                Supported,
                Supported[SERIALNUMBER],
                "NumServices", [Number of Services Used]
            ),
            [NumServices] >= MIN ( Services[Number of Services] ) && 
            [NumServices] <= MAX ( Services[Number of Services] )
        )
    )

People (Cumulative):

People (Cumulative) = 
    COUNTROWS ( 
        FILTER ( 
            SUMMARIZE ( 
                Supported,
                Supported[SERIALNUMBER],
                "NumServices", [Number of Services Used]
            ),
            [NumServices] >= MIN ( Services[Number of Services] )
        )
    )

This gives the following, for your (tiny) data sample:

enter image description here

我如何报告多个类别中的人数?

心在旅行 2025-02-18 19:11:15

您可以实现 sudo 。首先在/etc/sudoers 文件添加行类似于:

user1,user2,user2    ALL=/path/to/the/program

如果以上用户在特定组中,则可以添加类似的内容:

%usergroup   ALL=/path/to/the/program

并运行类似的程序:

sudo -u main_user /path/to/the/program

You can implement sudo. First in /etc/sudoers file add line like:

user1,user2,user2    ALL=/path/to/the/program

If the users above are in specific group you can add something like:

%usergroup   ALL=/path/to/the/program

And run the program like:

sudo -u main_user /path/to/the/program

使所有用户提供应用程序

心在旅行 2025-02-18 11:15:36

字符U+0000至U+001F直接从ASCII导入。如果它在ASCII中不存在,则在该范围内不存在Unicode中。

大多数是过时的;当今的频段定界符并没有太多使用。如果您使用带有带内定界符的现有协议,则它将具有基于ASCII使用的规则;如果您正在设计一个新协议,则可能有更好的方法进行。

据我所记得的,在典型的用法中不需要头脑结束,因为这与文本启动相吻合。大概是不需要进行传播的,因为您收到的第一件事是同步后传输的开始(在异步学科中启动位,SYNC中的SYNC)。

The characters U+0000 to U+001F are imported directly from ASCII. If it didn't exist in ASCII, it doesn't exist in Unicode, in that range.

Most are obsolete; in-band delimiters are not so much used nowadays. If you're using an existing protocol with in-band delimiters, it'll have rules based on ASCII usage; if you're designing a new protocol, there are probably better ways to proceed.

As far as I recall, there's no need for end-of-header in typical usage, because that's coincident with start-of-text. There's presumably no need for start-of-transmission because the first thing you receive is the start of transmission, after synchronization (start bits in async disciplines, SYN in sync).

标题的结尾或“传输的开始” unicode中的字符?

心在旅行 2025-02-18 09:31:28

socket.emit()将消息发送到socket.io连接的另一端。您不使用socket.io对自己不 .emit()。当 socket.emit(“ joinroom”)是从您的服务器发送的,它将消息发送给客户端,而不是向服务器发送。因此,这不会做您想做的事情。

您可以将代码从 Joinroom 放入共享功能中,并且可以从 Joinroom 事件处理程序和 createroom 事件处理程序中调用它。

您还可以将 joinroom createroom 的逻辑组合到一个事件中,如果要在加入之前创建的房间,则通过参数传递。然后,“加入”代码在两个操作中都在本地。

socket.emit() sends a message to the OTHER end of the socket.io connection. You do not .emit() to yourself with socket.io. When socket.emit("joinRoom") is sent from your server, it sends a message to the client, not to your server. So, that won't do what you want it to do.

You can put the code from joinRoom into a shared function and you can call it from both the joinRoom event handler and from the createRoom event handler.

You could also combine the logic for joinRoom and createRoom into one event where you pass an argument if you want the room created before joining. Then, the "join" code is right there locally for both operations.

在服务器端发出插座事件的插座事件是很好的做法吗

心在旅行 2025-02-18 06:02:00

用户 unconfinedTestDisPatcher()。这对我很好。

User UnconfinedTestDispatcher(). This worked for me very well.

MOCKK KOTLIN:验证失败:1个呼叫1:未调用

心在旅行 2025-02-18 03:36:57

我尝试了戈德的建议,这确实做到了。

开始-2022-06-29 14:44:00.847775

END B3DB INIT-0:00:00:02.259717

结束核心读取-0:00:00:00.485671

结束计算 - 0:00:

00.582443 :00.056849

END ORM Intancing -0:00:03.634285

END DADODB COMMIT- 0:00:00.963426

END DF.TO_SQL()提交 - 0:00.206448

总计 - 0:00:00:00:00:0:0:0:

08.188839数据框架,将其放入ORM实例和写作将大约需要4.5秒。仅运行DF.TO_SQL()方法将其完成为0.21s。

I have tried Gord's suggestion and that indeed did the trick.

Start -- 2022-06-29 14:44:00.847775

End B3DB Init -- 0:00:02.259717

End CORE Read -- 0:00:00.485671

End Calculations -- 0:00:00.582443

End DADODB Init -- 0:00:00.056849

End ORM Instancing -- 0:00:03.634285

End DADODB Commit -- 0:00:00.963426

End DF.to_sql() Commit -- 0:00:00.206448

Total -- 0:00:08.188839

Starting with the data in a dataframe, putting it into ORM instances and writing would take roughly 4.5s. Just running the DF.to_SQL() method gets it done in 0.21s.

有没有办法在启用SQLalchemy Orm对象时避免循环?

心在旅行 2025-02-18 02:41:46

您将使用SolidColorbrush作为Setter的值:

<Setter Property="Background"> 
    <Setter.Value> 
        <SolidColorBrush Color="{Binding}"/>
    </Setter.Value>
</Setter>

除此之外,ControlTemplate还必须使用背景属性:

<ControlTemplate TargetType="ListViewItem">
    <Grid Height="30" Width="30"
          Background="{TemplateBinding Background}"/>
</ControlTemplate>

另请注意,当您设置ListViewItem的模板之类的模板时,根本不使用 ItemTemplate 。 ControlTemplate应具有 contentPresenter

<ControlTemplate TargetType="ListViewItem">
    <Grid Height="30" Width="30"
          Background="{TemplateBinding Background}">
        <ContentPresenter/>
    </Grid>
</ControlTemplate>

You would use a SolidColorBrush as value of the Setter:

<Setter Property="Background"> 
    <Setter.Value> 
        <SolidColorBrush Color="{Binding}"/>
    </Setter.Value>
</Setter>

Besides that, the ControlTemplate must also use the Background property:

<ControlTemplate TargetType="ListViewItem">
    <Grid Height="30" Width="30"
          Background="{TemplateBinding Background}"/>
</ControlTemplate>

Also note that when you set the ListViewItem's Template like this, the ItemTemplate is not used at all. The ControlTemplate should have a ContentPresenter.

<ControlTemplate TargetType="ListViewItem">
    <Grid Height="30" Width="30"
          Background="{TemplateBinding Background}">
        <ContentPresenter/>
    </Grid>
</ControlTemplate>

如何在WPF ListView中绑定和显示一组颜色?

心在旅行 2025-02-18 02:35:20

在Laravel中使用逻辑分组,谢谢Aynber:

->where('id', 1111)
->where(function ($q) {
            $q->where('column2', 'sample')
            ->orWhereNull('column1');
        })

Use Logical Grouping in Laravel, thanks aynber:

->where('id', 1111)
->where(function ($q) {
            $q->where('column2', 'sample')
            ->orWhereNull('column1');
        })

我该如何查询在Laravel中构建

心在旅行 2025-02-17 21:09:43

因此,这是工作解决方案,您可以通过进行一些更改来实现想要的目标。该解决方案尚未完全优化,但是您会明白。

因此,为了获得结果,您必须创建一个具有实际日期编号的新数据数组,以便我们以后可以使用它来过滤 Dayarr 。之后,您必须在对象的一天中绘制映射,并检查一天与数据阵列的一天是否匹配,如果匹配该阵列,请更换小时。

import "./styles.css";
import React from "react";

export default function App() {
  const data = [
    {
      start: "2022-04-02",
      hours: 2
    },
    {
      start: "2022-04-06",
      hours: 3
    },
    {
      start: "2022-04-11",
      hours: 1
    }
  ];


  // filter the data so we can have actual day number
  const filteredData = data.map((item) => {
    const splitDate = item.start.split("-");
    const day = splitDate[splitDate.length - 1];

    return {
      start: parseInt(day),
      hours: item.hours
    };
  });


  const [newData, setNewData] = React.useState();

  const setDataforTable = () => {
    const dataDays = data.map((data) => ({
      day: new Date(data.start).getDate(),
      hours: data.hours
    }));

    setNewData(dataDays);
  };

  const [days, setDays] = React.useState([]);

  const settingDays = () => {
    const daysInMonth = 30;

    let dayInfo = [];
    for (let i = 1; i <= daysInMonth; i++) {
      dayInfo.push(i)

      // create an array and fill hours with 0
      const dayArr = dayInfo.map((day) => ({
        day: day,
        hours: 0
      }));


      // map over dayArr and replace the hours 
      let temp = [...dayArr];
      dayArr.map((i, idx) => {
        const getHours = filteredData.filter((item) => item.start === i.day);
        if (getHours.length) {
          const newData = {
            day: i.day,
            hours: getHours[0].hours
          };
          temp[idx] = newData;
        }
      });

      setDays(temp);
    }
  };

  const totalHours = data.map((i) => i.hours).reduce((a, b) => a + b, 0);

  let tableDisplay;


  if (days.length) {
    //convertData();
    tableDisplay = (
      <div>
        <table>
          <thead>
            <tr>
              <th> Date </th>
              {days.map((i) => (
                <th key={i}>{i?.day}</th>
              ))}
              <th>Total Hours</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td>Hours</td>
              {/* {newData &&
                
              } */}
              {days && days.map((d) => <td>{d.hours}</td>)}
              <td>{totalHours}</td>
            </tr>
          </tbody>
        </table>
      </div>
    );
  }

  return (
    <div>
      <button
        onClick={() => {
          setDataforTable();
          settingDays();
        }}
      >
        Click
      </button>
      {tableDisplay}
    </div>
  );
}

So, here's the working solution and you could achieve what you wanted by making some changes. This solution is not fully optimized but you'll get the idea.

So, in order to get the results you'll have to create an new array of data with actual date number so we could use it later for filtering the dayArr. After that you'll have to map over your day array of object and check if the day matches with day inside data array if it matches then replace the hours.

import "./styles.css";
import React from "react";

export default function App() {
  const data = [
    {
      start: "2022-04-02",
      hours: 2
    },
    {
      start: "2022-04-06",
      hours: 3
    },
    {
      start: "2022-04-11",
      hours: 1
    }
  ];


  // filter the data so we can have actual day number
  const filteredData = data.map((item) => {
    const splitDate = item.start.split("-");
    const day = splitDate[splitDate.length - 1];

    return {
      start: parseInt(day),
      hours: item.hours
    };
  });


  const [newData, setNewData] = React.useState();

  const setDataforTable = () => {
    const dataDays = data.map((data) => ({
      day: new Date(data.start).getDate(),
      hours: data.hours
    }));

    setNewData(dataDays);
  };

  const [days, setDays] = React.useState([]);

  const settingDays = () => {
    const daysInMonth = 30;

    let dayInfo = [];
    for (let i = 1; i <= daysInMonth; i++) {
      dayInfo.push(i)

      // create an array and fill hours with 0
      const dayArr = dayInfo.map((day) => ({
        day: day,
        hours: 0
      }));


      // map over dayArr and replace the hours 
      let temp = [...dayArr];
      dayArr.map((i, idx) => {
        const getHours = filteredData.filter((item) => item.start === i.day);
        if (getHours.length) {
          const newData = {
            day: i.day,
            hours: getHours[0].hours
          };
          temp[idx] = newData;
        }
      });

      setDays(temp);
    }
  };

  const totalHours = data.map((i) => i.hours).reduce((a, b) => a + b, 0);

  let tableDisplay;


  if (days.length) {
    //convertData();
    tableDisplay = (
      <div>
        <table>
          <thead>
            <tr>
              <th> Date </th>
              {days.map((i) => (
                <th key={i}>{i?.day}</th>
              ))}
              <th>Total Hours</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td>Hours</td>
              {/* {newData &&
                
              } */}
              {days && days.map((d) => <td>{d.hours}</td>)}
              <td>{totalHours}</td>
            </tr>
          </tbody>
        </table>
      </div>
    );
  }

  return (
    <div>
      <button
        onClick={() => {
          setDataforTable();
          settingDays();
        }}
      >
        Click
      </button>
      {tableDisplay}
    </div>
  );
}

反应在具有动态列的表中显示数据

更多

推荐作者

櫻之舞

文章 0 评论 0

弥枳

文章 0 评论 0

m2429

文章 0 评论 0

野却迷人

文章 0 评论 0

我怀念的。

文章 0 评论 0

更多

友情链接

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